bitkeeper revision 1.1159.217.1 (41e2ffe6fPYJ64PJlBbjQaLbd8AFuQ)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 10 Jan 2005 22:21:26 +0000 (22:21 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Mon, 10 Jan 2005 22:21:26 +0000 (22:21 +0000)
Many files:
  Device models imported from BOCHS, courtesy of Arun Sharma [arun.sharma@intel.com]
  new file

163 files changed:
.rootkeys
tools/ioemu/Makefile [new file with mode: 0644]
tools/ioemu/font/vga.bitmap.h [new file with mode: 0644]
tools/ioemu/gui/Makefile [new file with mode: 0644]
tools/ioemu/gui/Makefile.in [new file with mode: 0644]
tools/ioemu/gui/bitmaps/cdromd.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/cdromd.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/configbutton.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/configbutton.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/copy.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/copy.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/floppya.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/floppya.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/floppyb.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/floppyb.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/mouse.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/mouse.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/paste.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/paste.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/power.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/power.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/reset.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/reset.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/snapshot.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/snapshot.xpm [new file with mode: 0644]
tools/ioemu/gui/bitmaps/userbutton.h [new file with mode: 0644]
tools/ioemu/gui/bitmaps/userbutton.xpm [new file with mode: 0644]
tools/ioemu/gui/gui.cc [new file with mode: 0644]
tools/ioemu/gui/gui.h [new file with mode: 0644]
tools/ioemu/gui/icon_bochs.h [new file with mode: 0644]
tools/ioemu/gui/icon_bochs.xpm [new file with mode: 0644]
tools/ioemu/gui/keymap.cc [new file with mode: 0644]
tools/ioemu/gui/keymap.h [new file with mode: 0644]
tools/ioemu/gui/keymaps/convertmap.pl [new file with mode: 0644]
tools/ioemu/gui/keymaps/sdl-pc-de.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/sdl-pc-us.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-be.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-da.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-de.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-es.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-fr.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-it.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-se.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-uk.map [new file with mode: 0644]
tools/ioemu/gui/keymaps/x11-pc-us.map [new file with mode: 0644]
tools/ioemu/gui/nogui.cc [new file with mode: 0644]
tools/ioemu/gui/rfb.cc [new file with mode: 0644]
tools/ioemu/gui/rfb.h [new file with mode: 0644]
tools/ioemu/gui/rfbproto.h [new file with mode: 0644]
tools/ioemu/gui/sdl.h [new file with mode: 0644]
tools/ioemu/gui/sdlkeys.h [new file with mode: 0644]
tools/ioemu/gui/siminterface.cc [new file with mode: 0644]
tools/ioemu/gui/siminterface.h [new file with mode: 0644]
tools/ioemu/gui/svga.cc [new file with mode: 0644]
tools/ioemu/gui/term.cc [new file with mode: 0644]
tools/ioemu/gui/textconfig.cc [new file with mode: 0644]
tools/ioemu/gui/textconfig.h [new file with mode: 0644]
tools/ioemu/gui/x.cc [new file with mode: 0644]
tools/ioemu/include/bochs.h [new file with mode: 0644]
tools/ioemu/include/bxversion.h [new file with mode: 0644]
tools/ioemu/include/config.h [new file with mode: 0644]
tools/ioemu/include/cpu/cpu.h [new file with mode: 0644]
tools/ioemu/include/extplugin.h [new file with mode: 0644]
tools/ioemu/include/instrument.h [new file with mode: 0644]
tools/ioemu/include/ltdl.h [new file with mode: 0644]
tools/ioemu/include/ltdlconf.h [new file with mode: 0644]
tools/ioemu/include/osdep.h [new file with mode: 0644]
tools/ioemu/include/pc_system.h [new file with mode: 0644]
tools/ioemu/include/plugin.h [new file with mode: 0644]
tools/ioemu/include/state_file.h [new file with mode: 0644]
tools/ioemu/iodev/Makefile [new file with mode: 0644]
tools/ioemu/iodev/aspi-win32.h [new file with mode: 0644]
tools/ioemu/iodev/biosdev.cc [new file with mode: 0644]
tools/ioemu/iodev/biosdev.h [new file with mode: 0644]
tools/ioemu/iodev/cdrom.cc [new file with mode: 0644]
tools/ioemu/iodev/cdrom.h [new file with mode: 0644]
tools/ioemu/iodev/cdrom_beos.h [new file with mode: 0644]
tools/ioemu/iodev/cmos.cc [new file with mode: 0644]
tools/ioemu/iodev/cmos.h [new file with mode: 0644]
tools/ioemu/iodev/cpu.cc [new file with mode: 0644]
tools/ioemu/iodev/crc32.cc [new file with mode: 0644]
tools/ioemu/iodev/crc32.h [new file with mode: 0644]
tools/ioemu/iodev/devices.cc [new file with mode: 0644]
tools/ioemu/iodev/dma.cc [new file with mode: 0644]
tools/ioemu/iodev/dma.h [new file with mode: 0644]
tools/ioemu/iodev/eth.cc [new file with mode: 0644]
tools/ioemu/iodev/eth.h [new file with mode: 0644]
tools/ioemu/iodev/eth_arpback.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_fbsd.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_linux.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_null.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_packetmaker.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_packetmaker.h [new file with mode: 0644]
tools/ioemu/iodev/eth_tap.cc [new file with mode: 0644]
tools/ioemu/iodev/eth_tuntap.cc [new file with mode: 0644]
tools/ioemu/iodev/extfpuirq.cc [new file with mode: 0644]
tools/ioemu/iodev/extfpuirq.h [new file with mode: 0644]
tools/ioemu/iodev/floppy.cc [new file with mode: 0644]
tools/ioemu/iodev/floppy.h [new file with mode: 0644]
tools/ioemu/iodev/gameport.cc [new file with mode: 0644]
tools/ioemu/iodev/gameport.h [new file with mode: 0644]
tools/ioemu/iodev/guest2host.h [new file with mode: 0644]
tools/ioemu/iodev/harddrv.cc [new file with mode: 0644]
tools/ioemu/iodev/harddrv.h [new file with mode: 0644]
tools/ioemu/iodev/ioapic.cc [new file with mode: 0644]
tools/ioemu/iodev/ioapic.h [new file with mode: 0644]
tools/ioemu/iodev/iodebug.cc [new file with mode: 0644]
tools/ioemu/iodev/iodebug.h [new file with mode: 0644]
tools/ioemu/iodev/iodev.h [new file with mode: 0644]
tools/ioemu/iodev/keyboard.cc [new file with mode: 0644]
tools/ioemu/iodev/keyboard.h [new file with mode: 0644]
tools/ioemu/iodev/load32bitOShack.cc [new file with mode: 0644]
tools/ioemu/iodev/logio.cc [new file with mode: 0644]
tools/ioemu/iodev/main.cc [new file with mode: 0644]
tools/ioemu/iodev/ne2k.cc [new file with mode: 0644]
tools/ioemu/iodev/ne2k.h [new file with mode: 0644]
tools/ioemu/iodev/osdep.cc [new file with mode: 0644]
tools/ioemu/iodev/parallel.cc [new file with mode: 0644]
tools/ioemu/iodev/parallel.h [new file with mode: 0644]
tools/ioemu/iodev/pc_system.cc [new file with mode: 0644]
tools/ioemu/iodev/pci.cc [new file with mode: 0644]
tools/ioemu/iodev/pci.h [new file with mode: 0644]
tools/ioemu/iodev/pci2isa.cc [new file with mode: 0644]
tools/ioemu/iodev/pci2isa.h [new file with mode: 0644]
tools/ioemu/iodev/pciusb.cc [new file with mode: 0644]
tools/ioemu/iodev/pciusb.h [new file with mode: 0644]
tools/ioemu/iodev/pcivga.cc [new file with mode: 0644]
tools/ioemu/iodev/pcivga.h [new file with mode: 0644]
tools/ioemu/iodev/pic.cc [new file with mode: 0644]
tools/ioemu/iodev/pic.h [new file with mode: 0644]
tools/ioemu/iodev/pit.cc [new file with mode: 0644]
tools/ioemu/iodev/pit.h [new file with mode: 0644]
tools/ioemu/iodev/pit82c54.cc [new file with mode: 0644]
tools/ioemu/iodev/pit82c54.h [new file with mode: 0644]
tools/ioemu/iodev/pit_wrap.cc [new file with mode: 0644]
tools/ioemu/iodev/pit_wrap.h [new file with mode: 0644]
tools/ioemu/iodev/plugin.cc [new file with mode: 0644]
tools/ioemu/iodev/scancodes.cc [new file with mode: 0644]
tools/ioemu/iodev/scancodes.h [new file with mode: 0644]
tools/ioemu/iodev/scsi_commands.h [new file with mode: 0644]
tools/ioemu/iodev/scsidefs.h [new file with mode: 0644]
tools/ioemu/iodev/scsipt.h [new file with mode: 0644]
tools/ioemu/iodev/serial.cc [new file with mode: 0644]
tools/ioemu/iodev/serial.h [new file with mode: 0644]
tools/ioemu/iodev/serial_raw.h [new file with mode: 0644]
tools/ioemu/iodev/slowdown_timer.cc [new file with mode: 0644]
tools/ioemu/iodev/slowdown_timer.h [new file with mode: 0644]
tools/ioemu/iodev/soundlnx.cc [new file with mode: 0644]
tools/ioemu/iodev/soundlnx.h [new file with mode: 0644]
tools/ioemu/iodev/soundwin.cc [new file with mode: 0644]
tools/ioemu/iodev/soundwin.h [new file with mode: 0644]
tools/ioemu/iodev/state_file.cc [new file with mode: 0644]
tools/ioemu/iodev/unmapped.cc [new file with mode: 0644]
tools/ioemu/iodev/unmapped.h [new file with mode: 0644]
tools/ioemu/iodev/vga.cc [new file with mode: 0644]
tools/ioemu/iodev/vga.h [new file with mode: 0644]
tools/ioemu/iodev/virt_timer.cc [new file with mode: 0644]
tools/ioemu/iodev/virt_timer.h [new file with mode: 0644]
tools/ioemu/memory/Makefile [new file with mode: 0644]
tools/ioemu/memory/memory.cc [new file with mode: 0644]
tools/ioemu/memory/memory.h [new file with mode: 0644]
tools/ioemu/memory/misc_mem.cc [new file with mode: 0644]
tools/ioemu/mk/helix.mk [new file with mode: 0644]

index ca97aacf1228fe950ab1b5045340c67adeb15b76..1afa18ea51959f12798d0edc21248e800a57e28c 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 41dde8af6M2Pm1Rrv_f5jEFC_BIOIA tools/examples/xmexample.vmx
 41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1
 40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample2
+41e2ff6dNPgvIrdIF6dC1azdex1U3A tools/ioemu/Makefile
+41e2ff6aoF5fgddZi0QpEWqFr89E5g tools/ioemu/font/vga.bitmap.h
+41e2ff6avgnBNvZRiL4ynyGGq2UKlw tools/ioemu/gui/Makefile
+41e2ff6a30Xuw7pDX3SlVBx3ssOMDQ tools/ioemu/gui/Makefile.in
+41e2ff6aGGn5D3-Yh856G7xWJ5ZJsA tools/ioemu/gui/bitmaps/cdromd.h
+41e2ff6abNiWU34DwftxJ30sI6TQmw tools/ioemu/gui/bitmaps/cdromd.xpm
+41e2ff6adSUYHlvyVpz7q1Izcx5_gQ tools/ioemu/gui/bitmaps/configbutton.h
+41e2ff6aLWWXfMqIH2jSCNUzuc4_Yg tools/ioemu/gui/bitmaps/configbutton.xpm
+41e2ff6ahsqMjwuhpbqfrFHCBqYhEA tools/ioemu/gui/bitmaps/copy.h
+41e2ff6ajL41CnUeGefMrNijudQlCg tools/ioemu/gui/bitmaps/copy.xpm
+41e2ff6aXn5GhkDNOGqUcfCLbDZf3w tools/ioemu/gui/bitmaps/floppya.h
+41e2ff6agOpnECodSZ62L-Uijy5fsQ tools/ioemu/gui/bitmaps/floppya.xpm
+41e2ff6akrHp6jG_Y2BmFpEcaswUqg tools/ioemu/gui/bitmaps/floppyb.h
+41e2ff6aGbvPO1cQLMLduGl16rntbg tools/ioemu/gui/bitmaps/floppyb.xpm
+41e2ff6aEcsgeBHQZ_5e3rfgo0USMA tools/ioemu/gui/bitmaps/mouse.h
+41e2ff6aO8pXESvDVxMG7TgZL7UvFA tools/ioemu/gui/bitmaps/mouse.xpm
+41e2ff6aSd1H6Z0dUVUYLsW-6EDrYw tools/ioemu/gui/bitmaps/paste.h
+41e2ff6aRGfY6Jd2TThqWtXoh2CHuQ tools/ioemu/gui/bitmaps/paste.xpm
+41e2ff6aKDap56ifPVgdBVPc9yfmvw tools/ioemu/gui/bitmaps/power.h
+41e2ff6aDLfEO8dFUd9IpsfUpMk-Vg tools/ioemu/gui/bitmaps/power.xpm
+41e2ff6aKWtTsWCds4vL2azV3w-XtQ tools/ioemu/gui/bitmaps/reset.h
+41e2ff6a_AU4_ytzHU0Btr3trcbVmA tools/ioemu/gui/bitmaps/reset.xpm
+41e2ff6a-hGpcXEChJQDo-xRyH5oGQ tools/ioemu/gui/bitmaps/snapshot.h
+41e2ff6aRoGi5nKyQFtcUzK0-9dRDA tools/ioemu/gui/bitmaps/snapshot.xpm
+41e2ff6aZdTp9lSJjyUI7YoXqQnCng tools/ioemu/gui/bitmaps/userbutton.h
+41e2ff6aWc4p23rAKngLMu8eLZiXlw tools/ioemu/gui/bitmaps/userbutton.xpm
+41e2ff6a7gMd57Q5DL0kRD-mR7JzZg tools/ioemu/gui/gui.cc
+41e2ff6a-USvofVXiSpY76RT4C0IVw tools/ioemu/gui/gui.h
+41e2ff6aYAuOb0x4zTVB7cWYIFIdOA tools/ioemu/gui/icon_bochs.h
+41e2ff6aZbFf-Djysg393N4vCEJ7ig tools/ioemu/gui/icon_bochs.xpm
+41e2ff6ai-vJcSE9hfz4SHZ20rK5QA tools/ioemu/gui/keymap.cc
+41e2ff6a_TY9EJnCcbr5EKV_pi90kg tools/ioemu/gui/keymap.h
+41e2ff6aP0co3DAK04MrugZCkp0roQ tools/ioemu/gui/keymaps/convertmap.pl
+41e2ff6a-GiP9bzqtVXEjxmxiYgzeg tools/ioemu/gui/keymaps/sdl-pc-de.map
+41e2ff6aa5xj7jyze5bcPnj-UHYgTQ tools/ioemu/gui/keymaps/sdl-pc-us.map
+41e2ff6ahemkf0kG8SzDXq8g2qp9Pg tools/ioemu/gui/keymaps/x11-pc-be.map
+41e2ff6ajdaBBS85yriZ3S9ecy5Odg tools/ioemu/gui/keymaps/x11-pc-da.map
+41e2ff6aGkLyRvwOTZnDqvobziAoiQ tools/ioemu/gui/keymaps/x11-pc-de.map
+41e2ff6aWcqOK6RjpY28Y4bVjMy9yg tools/ioemu/gui/keymaps/x11-pc-es.map
+41e2ff6aF46Uu09XOmmkcGDotToSxw tools/ioemu/gui/keymaps/x11-pc-fr.map
+41e2ff6aHM040MYLmOeW_PKIx1TWWg tools/ioemu/gui/keymaps/x11-pc-it.map
+41e2ff6aCa-6fHjBOoPWP8hDweZ1Fw tools/ioemu/gui/keymaps/x11-pc-se.map
+41e2ff6aUH4wvnqRwo91dJBnhxEYUg tools/ioemu/gui/keymaps/x11-pc-uk.map
+41e2ff6aF7b08llRJQBLgNAEfyn9wQ tools/ioemu/gui/keymaps/x11-pc-us.map
+41e2ff6a2gbWdoaE7X9vtizvQ4QqdQ tools/ioemu/gui/nogui.cc
+41e2ff6a_rWAWre2toEtNUMKliCJPA tools/ioemu/gui/rfb.cc
+41e2ff6aQfuugiO3YE07l03L6ASP9g tools/ioemu/gui/rfb.h
+41e2ff6aTWFzmW0sjxXpQq7ulaj_Pw tools/ioemu/gui/rfbproto.h
+41e2ff6bf4pfJkZTN5vA6HbiJJqeNA tools/ioemu/gui/sdl.h
+41e2ff6bVnojmIqKJCbhVUKtMcUWJg tools/ioemu/gui/sdlkeys.h
+41e2ff6bKVx97oSdGGToXQXvbQgkZA tools/ioemu/gui/siminterface.cc
+41e2ff6bDB5XABCVAA7nMolZPe5ZoA tools/ioemu/gui/siminterface.h
+41e2ff6benMg1o7HQ2C5PGS3KFHFow tools/ioemu/gui/svga.cc
+41e2ff6bz3XZGzzwvXGqFadb3QqWWQ tools/ioemu/gui/term.cc
+41e2ff6b8jzKgyKu2gNVlRWepPNA0A tools/ioemu/gui/textconfig.cc
+41e2ff6bUKaJhGtIDqUYzAesLg1MGA tools/ioemu/gui/textconfig.h
+41e2ff6b__Pd6Q2aYDZ5vB9bGJEMNA tools/ioemu/gui/x.cc
+41e2ff6bp96y5NyMIFjH-HpCRcGBPg tools/ioemu/include/bochs.h
+41e2ff6bqIMIJlitAnubjNjf70s3dw tools/ioemu/include/bxversion.h
+41e2ff6bTfksDlUXSWC_wC_g30r1cQ tools/ioemu/include/config.h
+41e2ff6bwDEGCUwYTf1oo9ZCva2nkw tools/ioemu/include/cpu/cpu.h
+41e2ff6bH1PTh2iMScpOn9v9R3SDag tools/ioemu/include/extplugin.h
+41e2ff6bFS9XP8ndI6IhGFitzsvTtw tools/ioemu/include/instrument.h
+41e2ff6bz71jKff_NUdmI279ArbMgw tools/ioemu/include/ltdl.h
+41e2ff6bYayW_YSVmb1sJCvk9z9-ug tools/ioemu/include/ltdlconf.h
+41e2ff6b_MdkIIjsFYTFMIKIt7Royw tools/ioemu/include/osdep.h
+41e2ff6bPJNSITgePniKtvlujrmcLA tools/ioemu/include/pc_system.h
+41e2ff6bmHZyZrzF7iHpD212GeAT-w tools/ioemu/include/plugin.h
+41e2ff6bHgstm2ZhCIdsag_c3_dVjA tools/ioemu/include/state_file.h
+41e2ff6bJjm8-4K6Cu2k6zoanQ8Yyg tools/ioemu/iodev/Makefile
+41e2ff6bKj9bQ4ELP2msSYoT7XrxHQ tools/ioemu/iodev/aspi-win32.h
+41e2ff6b95DLt3iA-okw7D4NJcaDCg tools/ioemu/iodev/biosdev.cc
+41e2ff6b1ra22hFnE6Tm9lxVaH4Mjw tools/ioemu/iodev/biosdev.h
+41e2ff6bftET40KQA19RAisCxyDHVQ tools/ioemu/iodev/cdrom.cc
+41e2ff6buuSLUZPj9EtlGA3tufslNQ tools/ioemu/iodev/cdrom.h
+41e2ff6bvD6jE2JHKP0wd7I_mB7MJg tools/ioemu/iodev/cdrom_beos.h
+41e2ff6b99qviTPyKLjy0-D5DIqACw tools/ioemu/iodev/cmos.cc
+41e2ff6bpeZbWqQfuwM_Xj-kElElAA tools/ioemu/iodev/cmos.h
+41e2ff6bRf7QN_i1c7BAzkQha8AFUg tools/ioemu/iodev/cpu.cc
+41e2ff6byVHp6G3fxAlly1u1sx_DEg tools/ioemu/iodev/crc32.cc
+41e2ff6bHWz28hOKgLKRizX9UjsyOQ tools/ioemu/iodev/crc32.h
+41e2ff6b3tvq7uKSC9DWkOswq0Re8w tools/ioemu/iodev/devices.cc
+41e2ff6bO-SYXzx1RB-1If_FNkyjLg tools/ioemu/iodev/dma.cc
+41e2ff6bdI7Ri1mVb1MzkvBKlNSx6Q tools/ioemu/iodev/dma.h
+41e2ff6bfnGRrb25sneyvOXxSi8pLg tools/ioemu/iodev/eth.cc
+41e2ff6bteOXqvNO1FIR5iFHUwqUuA tools/ioemu/iodev/eth.h
+41e2ff6bTQxXrfWSsDCISUAdzlAe9w tools/ioemu/iodev/eth_arpback.cc
+41e2ff6brorlh9N9Myd1_g7ktKcIfQ tools/ioemu/iodev/eth_fbsd.cc
+41e2ff6b5xRFy8_OISEtd2UrHEUdfw tools/ioemu/iodev/eth_linux.cc
+41e2ff6biySiByowEn40XP_yx_lxKg tools/ioemu/iodev/eth_null.cc
+41e2ff6bFAVD0UO_ob40usJOnEPAZg tools/ioemu/iodev/eth_packetmaker.cc
+41e2ff6bsR-mjksFNRC9HiDDVUfI2w tools/ioemu/iodev/eth_packetmaker.h
+41e2ff6bMnzZ7cpqVPQY0_0smpqjHw tools/ioemu/iodev/eth_tap.cc
+41e2ff6bGa18jj0cqoOAqBPDzk2Aog tools/ioemu/iodev/eth_tuntap.cc
+41e2ff6bY1u244mkTGfttym3HoLo5Q tools/ioemu/iodev/extfpuirq.cc
+41e2ff6b_wh3dgYBx38KIJ00Qv4XUA tools/ioemu/iodev/extfpuirq.h
+41e2ff6b3uiKo02slxJn11bvZKsF3g tools/ioemu/iodev/floppy.cc
+41e2ff6bKba0nlJHGy2kWUr_3e_nvw tools/ioemu/iodev/floppy.h
+41e2ff6bC1KaCAEBYYTkJJ5_pBydkQ tools/ioemu/iodev/gameport.cc
+41e2ff6bePGww4K0p8vTLphdE_zdig tools/ioemu/iodev/gameport.h
+41e2ff6biLQpMiiiKokz7qUXpBn5cg tools/ioemu/iodev/guest2host.h
+41e2ff6bji1Iix0CzQTeh9yB-Ao14Q tools/ioemu/iodev/harddrv.cc
+41e2ff6bcSDALK1SdvKvTCxemzpWwQ tools/ioemu/iodev/harddrv.h
+41e2ff6b36hFBfV06tX0a5CRjFpuxA tools/ioemu/iodev/ioapic.cc
+41e2ff6brajF6a0a7RkLHiX0M9oH7w tools/ioemu/iodev/ioapic.h
+41e2ff6btDX2IfOnC_LkP08ZlKxjJw tools/ioemu/iodev/iodebug.cc
+41e2ff6b-__Z4ECo9pHWVM-Rz-0ehw tools/ioemu/iodev/iodebug.h
+41e2ff6btRbGfsUt5k4MClieCZ-EBQ tools/ioemu/iodev/iodev.h
+41e2ff6bH5C9aG3f2QhoD6zCdShJYQ tools/ioemu/iodev/keyboard.cc
+41e2ff6bUOmeloSf5s9Gkdffo1bEyA tools/ioemu/iodev/keyboard.h
+41e2ff6b55oybF1yhInYSZX2bxiJSw tools/ioemu/iodev/load32bitOShack.cc
+41e2ff6b5WcmfYXaREzUm0KQu7pKCQ tools/ioemu/iodev/logio.cc
+41e2ff6bqqHfrDtizlRKA-_oPRbGAw tools/ioemu/iodev/main.cc
+41e2ff6cWAAGa6Pt6eE4URbCOq8wQA tools/ioemu/iodev/ne2k.cc
+41e2ff6cap6qrVL42AgTpxjav0QMQg tools/ioemu/iodev/ne2k.h
+41e2ff6cHH0UoJW74RKZFnPBSt1jUw tools/ioemu/iodev/osdep.cc
+41e2ff6ckuFNtxuAQDMVwJtYwL2QCg tools/ioemu/iodev/parallel.cc
+41e2ff6cbqWnJwLAQ9NDZJwUyGiIww tools/ioemu/iodev/parallel.h
+41e2ff6cAdkxmfzVhbQn9Plq3X4S_w tools/ioemu/iodev/pc_system.cc
+41e2ff6csu1e9S_rywWOq9B85IaZzA tools/ioemu/iodev/pci.cc
+41e2ff6cjcmNZLD17naGuKj_Qon6Ow tools/ioemu/iodev/pci.h
+41e2ff6c91zYiAb9XulXkl2vLERo-w tools/ioemu/iodev/pci2isa.cc
+41e2ff6cV7IdLNbFXwlWvdcOz4F1Aw tools/ioemu/iodev/pci2isa.h
+41e2ff6cviwF37ZllnYtHA3MEHRMWw tools/ioemu/iodev/pciusb.cc
+41e2ff6ceFmfyqr1MgYhEoRM1s6icQ tools/ioemu/iodev/pciusb.h
+41e2ff6cd-1VHyISVo789tv3ImNgLw tools/ioemu/iodev/pcivga.cc
+41e2ff6cVkXDlrNUTdt7D6BULEp1Tg tools/ioemu/iodev/pcivga.h
+41e2ff6c3xjAFB8X5OLFz_8Of62v2Q tools/ioemu/iodev/pic.cc
+41e2ff6c4UHzse5_N0Mx6u5dqKrVkw tools/ioemu/iodev/pic.h
+41e2ff6cdD9yovRmQNNJu8QVtZg7Iw tools/ioemu/iodev/pit.cc
+41e2ff6cXtvewmYJyoxrWGic2sOayg tools/ioemu/iodev/pit.h
+41e2ff6cXaqNRxMagdpNiT1kTWJJUA tools/ioemu/iodev/pit82c54.cc
+41e2ff6cHAkpKzMwyz3diMZWTswxmg tools/ioemu/iodev/pit82c54.h
+41e2ff6cMK9E2gjqHoWV9ZQfz-cP1Q tools/ioemu/iodev/pit_wrap.cc
+41e2ff6cbie7fPpQMgBImJ885GAPdw tools/ioemu/iodev/pit_wrap.h
+41e2ff6c0wLrWtBHxxboIzHsrZzkRA tools/ioemu/iodev/plugin.cc
+41e2ff6cN4Z6pnguPQaqiCkWp42MOQ tools/ioemu/iodev/scancodes.cc
+41e2ff6chK1sqb78l1sqhF3fJhjzBw tools/ioemu/iodev/scancodes.h
+41e2ff6cIyPvY7hNE5rP_PMZELhyVw tools/ioemu/iodev/scsi_commands.h
+41e2ff6cF3wH8A_66_yG92Wk7I2IWQ tools/ioemu/iodev/scsidefs.h
+41e2ff6cbAin6eD3Gfz2CozOS4_bwA tools/ioemu/iodev/scsipt.h
+41e2ff6cce6mNXZPGmlQ1bg_I0ef8Q tools/ioemu/iodev/serial.cc
+41e2ff6cxsITO-ikpd4vBYZUYO3qSw tools/ioemu/iodev/serial.h
+41e2ff6cbaCEgMJ92UELiRE2wEYe3g tools/ioemu/iodev/serial_raw.h
+41e2ff6cwDKTU8OukKNBNMDiAYUWvQ tools/ioemu/iodev/slowdown_timer.cc
+41e2ff6cM5XYdcgL417IBOzW-QipFg tools/ioemu/iodev/slowdown_timer.h
+41e2ff6c5X0WxdBPUyZlNmW6Zv_LRQ tools/ioemu/iodev/soundlnx.cc
+41e2ff6cIuE1VxGF_L6rdBtD6rZ_aA tools/ioemu/iodev/soundlnx.h
+41e2ff6cDIv87LKamP0Y-yjrdqALzQ tools/ioemu/iodev/soundwin.cc
+41e2ff6cB55j_uYIqYh-UiLS4wlm_g tools/ioemu/iodev/soundwin.h
+41e2ff6dRPBmtxjFbEM5WYuilnSSZg tools/ioemu/iodev/state_file.cc
+41e2ff6dMwkI1Dpa-UHSEzHCvjpOyw tools/ioemu/iodev/unmapped.cc
+41e2ff6d_yJMFHYPENtVmJz6wyldQA tools/ioemu/iodev/unmapped.h
+41e2ff6dU5hJI6Kn70mFingJo4cHUw tools/ioemu/iodev/vga.cc
+41e2ff6dh8xDcCXkZzpSqnFP-OXggw tools/ioemu/iodev/vga.h
+41e2ff6dayXwb5dxf0K5pd3q4QppRA tools/ioemu/iodev/virt_timer.cc
+41e2ff6dI_rNgBwki594UAWN337-zw tools/ioemu/iodev/virt_timer.h
+41e2ff6dCCtE_btrlEopLaCsLO3JDA tools/ioemu/memory/Makefile
+41e2ff6dZtwsTW8s-Gqv7bqObdvaXw tools/ioemu/memory/memory.cc
+41e2ff6dpk6EFzlHlsAsFEFdyG4wrA tools/ioemu/memory/memory.h
+41e2ff6d2i-wqgCe4iAXdckUc1GD-A tools/ioemu/memory/misc_mem.cc
+41e2ff6dCYuZgf6pxRmphkh5yeuA9Q tools/ioemu/mk/helix.mk
 3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile
 41dde8afKYRKxS4XtLv1KUegGQy_bg tools/libxc/linux_boot_params.h
 41cc934abX-QLXJXW_clV_wRjM0zYg tools/libxc/plan9a.out.h
diff --git a/tools/ioemu/Makefile b/tools/ioemu/Makefile
new file mode 100644 (file)
index 0000000..78a16a7
--- /dev/null
@@ -0,0 +1,19 @@
+# Order is important!
+SUBDIRS=gui memory iodev
+
+all: $(SUBDIRS)
+
+$(SUBDIRS):
+       $(MAKE) -C $@
+
+.PHONY: all $(SUBDIRS)
+
+clean:
+       @for subdir in $(SUBDIRS); do                           \
+               $(MAKE) -C $$subdir $(MAKEDEFS) $@ || exit -1;  \
+       done
+
+install:
+       @for subdir in $(SUBDIRS); do                           \
+               $(MAKE) -C $$subdir $(MAKEDEFS) $@ || exit -1;  \
+       done
diff --git a/tools/ioemu/font/vga.bitmap.h b/tools/ioemu/font/vga.bitmap.h
new file mode 100644 (file)
index 0000000..e82dd62
--- /dev/null
@@ -0,0 +1,288 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.bitmap.h,v 1.4 2002/05/25 14:22:53 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+typedef struct {
+  unsigned char data[16];
+  } bx_fontcharbitmap_t;
+
+static const bx_fontcharbitmap_t bx_vgafont[256] = {
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xa5, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xdb, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x78, 0x60, 0x70, 0x58, 0x1e, 0x33, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfc, 0xcc, 0xfc, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xe6, 0xe7, 0x67, 0x03, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7f, 0x7c, 0x78, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0xfe, 0xdb, 0xdb, 0xdb, 0xde, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x36, 0x63, 0x63, 0x36, 0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x36, 0x7f, 0x36, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x3e, 0x60, 0x60, 0x61, 0x63, 0x3e, 0x18, 0x18, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x30, 0x18, 0x0c, 0x06, 0x63, 0x61, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0c, 0x0c, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x6b, 0x6b, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x60, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7b, 0x7b, 0x7b, 0x3b, 0x03, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, 0x66, 0x5c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x77, 0x7f, 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x7b, 0x3e, 0x30, 0x70, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30, 0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x77, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x63, 0x36, 0x3e, 0x1c, 0x1c, 0x3e, 0x36, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x61, 0x30, 0x18, 0x0c, 0x06, 0x43, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00 }},
+{{ 0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x00 }},
+{{ 0x00, 0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1e, 0x1e, 0x36, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0x78, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x6b, 0x6b, 0x6b, 0x7f, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1c, 0x1c, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1f, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x33, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x43, 0x66, 0x3c, 0x30, 0x60, 0x3e, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x33, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x33, 0x00, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x1c, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06, 0x66, 0x3c, 0x30, 0x60, 0x3c, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x1c, 0x36, 0x1c, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x0c, 0x06, 0x00, 0x7f, 0x66, 0x06, 0x3e, 0x06, 0x06, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x6e, 0x6c, 0x7e, 0x1b, 0x1b, 0x76, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33, 0x33, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0c, 0x1e, 0x33, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x06, 0x0c, 0x18, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x63, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1e, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x06, 0x06, 0x06, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x67, 0x3f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1f, 0x33, 0x33, 0x1f, 0x23, 0x33, 0x7b, 0x33, 0x33, 0x33, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x70, 0xd8, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x18, 0x0c, 0x06, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6e, 0x3b, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x3c, 0x36, 0x36, 0x7c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x06, 0x03, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x06, 0x3b, 0x61, 0x30, 0x18, 0x7c, 0x00, 0x00 }},
+{{ 0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x73, 0x79, 0x7c, 0x60, 0x60, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b, 0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 }},
+{{ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 }},
+{{ 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }},
+{{ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f }},
+{{ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }},
+{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x1b, 0x1b, 0x3b, 0x6e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x1b, 0x33, 0x63, 0x63, 0x63, 0x33, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x7f, 0x63, 0x63, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x7f, 0x63, 0x06, 0x0c, 0x18, 0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x03, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x36, 0x36, 0x36, 0x36, 0x77, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0xc0, 0x60, 0x7e, 0xdb, 0xdb, 0xcf, 0x7e, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x38, 0x0c, 0x06, 0x06, 0x3e, 0x06, 0x06, 0x06, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x70, 0xd8, 0xd8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 }},
+{{ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37, 0x36, 0x36, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x1b, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x0e, 0x1b, 0x0c, 0x06, 0x13, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
+};
diff --git a/tools/ioemu/gui/Makefile b/tools/ioemu/gui/Makefile
new file mode 100644 (file)
index 0000000..402c70c
--- /dev/null
@@ -0,0 +1,10 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS= gui.o keymap.o siminterface.o textconfig.o x.o
+
+all: libgui.a
+
+libgui.a: $(OBJS)
+       $(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(TOPDIR)/mk/helix.mk
diff --git a/tools/ioemu/gui/Makefile.in b/tools/ioemu/gui/Makefile.in
new file mode 100644 (file)
index 0000000..c9fd865
--- /dev/null
@@ -0,0 +1,561 @@
+# Copyright (C) 2002  MandrakeSoft S.A.
+#
+#   MandrakeSoft S.A.
+#   43, rue d'Aboukir
+#   75002 Paris - France
+#   http://www.linux-mandrake.com/
+#   http://www.mandrakesoft.com/
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+# Makefile for the gui component of bochs
+
+
+@SUFFIX_LINE@
+
+prefix          = @prefix@
+exec_prefix     = @exec_prefix@
+srcdir          = @srcdir@
+VPATH = @srcdir@
+bindir          = @bindir@
+libdir          = @libdir@
+mandir          = @mandir@
+man1dir         = $(mandir)/man1
+man5dir         = $(mandir)/man5
+docdir          = $(prefix)/share/doc/bochs
+sharedir        = $(prefix)/share/bochs
+top_builddir    = ..
+top_srcdir      = @top_srcdir@
+
+SHELL = /bin/sh
+
+@SET_MAKE@
+
+CXX = @CXX@
+CXXFLAGS = $(BX_INCDIRS) @CXXFLAGS@  @GUI_CXXFLAGS@
+LOCAL_CXXFLAGS =
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+X_CFLAGS = @X_CFLAGS@
+RANLIB = @RANLIB@
+PLUGIN_PATH=@libdir@
+top_builddir    = ..
+LIBTOOL=@LIBTOOL@
+WIN32_DLL_IMPORT_LIBRARY=../dllexports.a
+BX_INCDIRS = -I.. -I$(srcdir)/.. -I../iodev -I$(srcdir)/../iodev -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
+
+GUI_OBJS_X11  = x.o
+GUI_OBJS_SDL = sdl.o
+GUI_OBJS_SVGA = svga.o
+GUI_OBJS_BEOS = beos.o
+GUI_OBJS_WIN32 = win32.o
+GUI_OBJS_MACOS = macintosh.o
+GUI_OBJS_CARBON = carbon.o
+GUI_OBJS_NOGUI = nogui.o
+GUI_OBJS_TERM  = term.o
+GUI_OBJS_RFB = rfb.o
+GUI_OBJS_AMIGAOS = amigaos.o
+GUI_OBJS_WX = wx.o
+GUI_OBJS_WX_SUPPORT = wxmain.o wxdialog.o
+OBJS_THAT_CANNOT_BE_PLUGINS = keymap.o gui.o siminterface.o textconfig.o @DIALOG_OBJS@
+OBJS_THAT_CAN_BE_PLUGINS = @GUI_OBJS@
+
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+GUI_LINK_OPTS_X = $(X_LIBS) $(X_PRE_LIBS) -lX11 -lXpm
+GUI_LINK_OPTS_SDL = `sdl-config --cflags --libs`
+GUI_LINK_OPTS_SVGA =  -lvga -lvgagl
+GUI_LINK_OPTS_BEOS = -lbe
+GUI_LINK_OPTS_RFB = @RFB_LIBS@
+GUI_LINK_OPTS_AMIGAOS = 
+GUI_LINK_OPTS_WIN32 = -luser32 -lgdi32 -lcomdlg32 -lcomctl32
+GUI_LINK_OPTS_WIN32_VCPP = user32.lib gdi32.lib winmm.lib \
+  comdlg32.lib comctl32.lib wsock32.lib
+GUI_LINK_OPTS_MACOS =
+GUI_LINK_OPTS_CARBON = -framework Carbon
+GUI_LINK_OPTS_NOGUI =
+GUI_LINK_OPTS_TERM = @GUI_LINK_OPTS_TERM@
+GUI_LINK_OPTS_WX = @GUI_LINK_OPTS_WX@
+GUI_LINK_OPTS = @GUI_LINK_OPTS@  @DEVICE_LINK_OPTS@
+
+NONPLUGIN_OBJS = @GUI_NON_PLUGIN_OBJS@
+PLUGIN_OBJS = @GUI_PLUGIN_OBJS@
+
+#
+# -------- end configurable options --------------------------
+#
+
+all: libgui.a 
+
+plugins: $(PLUGIN_OBJS:@PLUGIN_LIBNAME_TRANSFORMATION@)
+
+libgui.a: $(NONPLUGIN_OBJS)
+       @RMCOMMAND@ libgui.a
+       @MAKELIB@ $(NONPLUGIN_OBJS)
+       @RANLIB@ libgui.a
+
+# standard compile rule for C++ files
+.@CPP_SUFFIX@.o:
+       $(CXX) @DASH@c  $(CXXFLAGS) $(LOCAL_CXXFLAGS) @CXXFP@$< @OFP@$@
+
+##### building plugins with libtool
+%.lo: %.@CPP_SUFFIX@
+       $(LIBTOOL) --mode=compile $(CXX) -c $(CXXFLAGS) $(LOCAL_CXXFLAGS) $< -o $@
+
+libbx_%.la: %.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH)
+
+libbx_x.la: x.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_X)
+
+libbx_sdl.la: sdl.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SDL)
+
+libbx_svga.la: svga.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_SVGA)
+
+libbx_beos.la: beos.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_BEOS)
+
+libbx_rfb.la: rfb.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_RFB)
+
+libbx_amigaos.la: amigaos.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_AMIGAOS)
+
+libbx_win32.la: win32.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_WIN32)
+
+libbx_macos.la: macos.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_MACOS)
+
+libbx_carbon.la: carbon.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_CARBON)
+
+libbx_nogui.la: nogui.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_NOGUI)
+
+libbx_term.la: term.lo
+       $(LIBTOOL) --mode=link $(CXX) -module $< -o $@ -rpath $(PLUGIN_PATH) $(GUI_LINK_OPTS_TERM)
+
+# special link rules for plugins that require more than one object file
+libbx_wx.la: $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo)
+       $(LIBTOOL) --mode=link $(CXX) -module $(GUI_OBJS_WX:.o=.lo) $(GUI_OBJS_WX_SUPPORT:.o=.lo) -o libbx_wx.la -rpath $(PLUGIN_PATH)  $(GUI_LINK_OPTS_WX)
+
+#### building DLLs for win32  (tested on cygwin only)
+bx_%.dll: %.o
+       $(CXX) $(CXXFLAGS) -shared -o $@ $< $(WIN32_DLL_IMPORT_LIBRARY)  $(GUI_LINK_OPTS_WIN32)
+
+bx_wx.dll: $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT)
+       $(CXX) $(CXXFLAGS) -shared -o bx_wx.dll $(GUI_OBJS_WX) $(GUI_OBJS_WX_SUPPORT) $(WIN32_DLL_IMPORT_LIBRARY) `wx-config --libs` -luser32 -lgdi32 -lcomdlg32 -lcomctl32
+
+bx_sdl.dll: $(GUI_OBJS_SDL) 
+       $(CXX) $(CXXFLAGS) -shared -o bx_sdl.dll $(GUI_OBJS_SDL) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_SDL)
+
+bx_rfb.dll: $(GUI_OBJS_RFB) 
+       $(CXX) $(CXXFLAGS) -shared -o bx_rfb.dll $(GUI_OBJS_RFB) $(WIN32_DLL_IMPORT_LIBRARY) $(GUI_LINK_OPTS_RFB)
+
+# no need to build DLLs for beos.o
+# no need to build DLLs for x.o
+
+##### end DLL section
+
+clean:
+       @RMCOMMAND@ -rf .libs *.la *.a *.lo *.o *.dll
+
+dist-clean: clean
+       @RMCOMMAND@ Makefile
+
+###########################################
+# all other dependencies generated by
+#  gcc -MM -I.. -I../instrument/stubs `wx-config --cxxflags` *.cc | 
+#     sed -e 's/\.cc/.@CPP_SUFFIX@/g'
+#  gcc -MM -I.. -I../instrument/stubs `wx-config --cxxflags` *.cc | \
+#     sed -e 's/\.cc/.@CPP_SUFFIX@/g' -e 's/\.o:/.lo:/g'
+#
+# This means that every source file is listed twice, once with a .o rule
+# and then again with an identical .lo rule.  The .lo rules are used when
+# building plugins.
+###########################################
+amigaos.o: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h amigagui.h
+beos.o: beos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../font/vga.bitmap.h
+carbon.o: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+gui.o: gui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/bitmaps/floppya.h \
+ ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h \
+ ../gui/bitmaps/reset.h ../gui/bitmaps/power.h \
+ ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \
+ ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \
+ ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h
+keymap.o: keymap.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h
+macintosh.o: macintosh.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h ../font/vga.bitmap.h
+nogui.o: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+rfb.o: rfb.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h \
+ rfbproto.h
+sdl.o: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h sdl.h sdlkeys.h
+siminterface.o: siminterface.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h
+svga.o: svga.@CPP_SUFFIX@ ../font/vga.bitmap.h ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h
+term.o: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+textconfig.o: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h textconfig.h \
+ siminterface.h ../extplugin.h ../ltdl.h
+win32.o: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+wx.o: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/icon_bochs.h \
+ ../font/vga.bitmap.h wxmain.h
+wxdialog.o: wxdialog.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h
+wxmain.o: wxmain.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h ../extplugin.h ../ltdl.h \
+ bitmaps/cdromd.xpm bitmaps/copy.xpm bitmaps/floppya.xpm \
+ bitmaps/floppyb.xpm bitmaps/paste.xpm bitmaps/power.xpm \
+ bitmaps/reset.xpm bitmaps/snapshot.xpm bitmaps/mouse.xpm \
+ bitmaps/userbutton.xpm
+x.o: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+amigaos.lo: amigaos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h amigagui.h
+beos.lo: beos.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../font/vga.bitmap.h
+carbon.lo: carbon.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+gui.lo: gui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/bitmaps/floppya.h \
+ ../gui/bitmaps/floppyb.h ../gui/bitmaps/mouse.h \
+ ../gui/bitmaps/reset.h ../gui/bitmaps/power.h \
+ ../gui/bitmaps/snapshot.h ../gui/bitmaps/copy.h \
+ ../gui/bitmaps/paste.h ../gui/bitmaps/configbutton.h \
+ ../gui/bitmaps/cdromd.h ../gui/bitmaps/userbutton.h
+keymap.lo: keymap.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h
+macintosh.lo: macintosh.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h ../font/vga.bitmap.h
+nogui.lo: nogui.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+rfb.lo: rfb.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h \
+ rfbproto.h
+sdl.lo: sdl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h sdl.h sdlkeys.h
+siminterface.lo: siminterface.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h
+svga.lo: svga.@CPP_SUFFIX@ ../font/vga.bitmap.h ../bochs.h ../config.h ../osdep.h \
+ ../bx_debug/debug.h ../bxversion.h ../gui/siminterface.h ../state_file.h \
+ ../cpu/cpu.h ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h \
+ ../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
+ ../gui/textconfig.h ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h \
+ ../iodev/biosdev.h ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h \
+ ../iodev/harddrv.h ../iodev/cdrom.h ../iodev/keyboard.h \
+ ../iodev/parallel.h ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h \
+ ../iodev/pit82c54.h ../iodev/serial.h ../iodev/unmapped.h \
+ ../iodev/eth.h ../iodev/ne2k.h ../iodev/guest2host.h \
+ ../iodev/slowdown_timer.h ../instrument/stubs/instrument.h \
+ icon_bochs.h
+term.lo: term.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
+textconfig.lo: textconfig.@CPP_SUFFIX@ ../config.h ../osdep.h textconfig.h \
+ siminterface.h ../extplugin.h ../ltdl.h
+win32.lo: win32.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h ../font/vga.bitmap.h
+wx.lo: wx.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h ../gui/icon_bochs.h \
+ ../font/vga.bitmap.h wxdialog.h wxmain.h
+wxdialog.lo: wxdialog.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h
+wxmain.lo: wxmain.@CPP_SUFFIX@ ../config.h ../osdep.h ../gui/siminterface.h \
+ ../bxversion.h wxdialog.h wxmain.h ../extplugin.h ../ltdl.h \
+ bitmaps/cdromd.xpm bitmaps/copy.xpm bitmaps/floppya.xpm \
+ bitmaps/floppyb.xpm bitmaps/paste.xpm bitmaps/power.xpm \
+ bitmaps/reset.xpm bitmaps/snapshot.xpm bitmaps/mouse.xpm \
+ bitmaps/userbutton.xpm
+x.lo: x.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
+ ../bxversion.h ../gui/siminterface.h ../state_file.h ../cpu/cpu.h \
+ ../cpu/lazy_flags.h ../cpu/i387.h ../memory/memory.h ../pc_system.h \
+ ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h ../gui/textconfig.h \
+ ../gui/keymap.h ../iodev/iodev.h ../iodev/vga.h ../iodev/biosdev.h \
+ ../iodev/cmos.h ../iodev/dma.h ../iodev/floppy.h ../iodev/harddrv.h \
+ ../iodev/cdrom.h ../iodev/keyboard.h ../iodev/parallel.h \
+ ../iodev/pic.h ../iodev/pit.h ../iodev/pit_wrap.h ../iodev/pit82c54.h \
+ ../iodev/serial.h ../iodev/unmapped.h ../iodev/eth.h ../iodev/ne2k.h \
+ ../iodev/guest2host.h ../iodev/slowdown_timer.h \
+ ../instrument/stubs/instrument.h icon_bochs.h
diff --git a/tools/ioemu/gui/bitmaps/cdromd.h b/tools/ioemu/gui/bitmaps/cdromd.h
new file mode 100644 (file)
index 0000000..49d78e1
--- /dev/null
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdromd.h,v 1.1 2002/01/31 21:16:52 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_CDROMD_BMAP_X 32
+#define BX_CDROMD_BMAP_Y 32
+
+static const unsigned char bx_cdromd_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x0e, 0x00, 0x00, 0x10, 0x12, 0x00, 
+  0x00, 0x10, 0x12, 0x00, 0x00, 0x10, 0x12, 0x00, 0x00, 0x60, 0x0e, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x0c, 0x30, 0x00, 
+  0x00, 0xe2, 0x47, 0x00, 0x00, 0x19, 0x98, 0x00, 0x80, 0xe6, 0x67, 0x01, 
+  0x40, 0x19, 0x98, 0x02, 0x20, 0xe5, 0xa7, 0x04, 0xa0, 0x12, 0x48, 0x05, 
+  0x90, 0xca, 0x53, 0x09, 0x50, 0x25, 0xa4, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 
+  0x50, 0x15, 0xa8, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 
+  0x50, 0x25, 0xa4, 0x0a, 0x90, 0xca, 0x53, 0x09, 0xa0, 0x12, 0x48, 0x05, 
+  0x20, 0xe5, 0xa7, 0x04, 0x40, 0x19, 0x98, 0x02, 0x80, 0xe6, 0x67, 0x01, 
+  0x00, 0x19, 0x98, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0x0c, 0x30, 0x00, 
+  0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+static const unsigned char bx_cdromd_eject_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+  0x01, 0x00, 0x00, 0x80, 0x02, 0x60, 0x0e, 0x40, 0x04, 0x10, 0x12, 0x20, 
+  0x08, 0x10, 0x12, 0x10, 0x10, 0x10, 0x12, 0x08, 0x20, 0x60, 0x0e, 0x04, 
+  0x40, 0x00, 0x00, 0x02, 0x80, 0xf0, 0x0f, 0x01, 0x00, 0x0d, 0xb0, 0x00, 
+  0x00, 0xe2, 0x47, 0x00, 0x00, 0x1d, 0xb8, 0x00, 0x80, 0xee, 0x77, 0x01, 
+  0x40, 0x19, 0x98, 0x02, 0x20, 0xe5, 0xa7, 0x04, 0xa0, 0x52, 0x4a, 0x05, 
+  0x90, 0xca, 0x53, 0x09, 0x50, 0xa5, 0xa5, 0x0a, 0x50, 0x55, 0xaa, 0x0a, 
+  0x50, 0x35, 0xac, 0x0a, 0x50, 0x15, 0xa8, 0x0a, 0x50, 0x1d, 0xb8, 0x0a, 
+  0x50, 0x25, 0xa4, 0x0a, 0x90, 0xca, 0x53, 0x09, 0xa0, 0x13, 0xc8, 0x05, 
+  0xa0, 0xe5, 0xa7, 0x05, 0x40, 0x19, 0x98, 0x02, 0xa0, 0xe6, 0x67, 0x05, 
+  0x10, 0x19, 0x98, 0x08, 0x08, 0xe2, 0x47, 0x10, 0x04, 0x0c, 0x30, 0x20, 
+  0x02, 0xf0, 0x0f, 0x40, 0x01, 0x00, 0x00, 0x80
+  };
diff --git a/tools/ioemu/gui/bitmaps/cdromd.xpm b/tools/ioemu/gui/bitmaps/cdromd.xpm
new file mode 100644 (file)
index 0000000..7a216b0
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *cdromd_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............##..###............",
+"............#....#..#...........",
+"............#....#..#...........",
+"............#....#..#...........",
+".............##..###............",
+"................................",
+"............########............",
+"..........##........##..........",
+".........#...######...#.........",
+"........#..##......##..#........",
+".......#.##..######..##.#.......",
+"......#.#..##......##..#.#......",
+".....#..#.#..######..#.#..#.....",
+".....#.#.#..#......#..#.#.#.....",
+"....#..#.#.#..####..#.#.#..#....",
+"....#.#.#.#..#....#..#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#.#......#.#.#.#.#....",
+"....#.#.#.#..#....#..#.#.#.#....",
+"....#..#.#.#..####..#.#.#..#....",
+".....#.#.#..#......#..#.#.#.....",
+".....#..#.#..######..#.#..#.....",
+"......#.#..##......##..#.#......",
+".......#.##..######..##.#.......",
+"........#..##......##..#........",
+".........#...######...#.........",
+"..........##........##..........",
+"............########............",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/configbutton.h b/tools/ioemu/gui/bitmaps/configbutton.h
new file mode 100644 (file)
index 0000000..7c51ff9
--- /dev/null
@@ -0,0 +1,16 @@
+#define BX_CONFIG_BMAP_X 32
+#define BX_CONFIG_BMAP_Y 32
+
+static const unsigned char bx_config_bmap[(BX_CONFIG_BMAP_X * BX_CONFIG_BMAP_Y)/8] = {
+  0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x01, 0xfc, 0x7f, 0xc0, 0x03, 
+  0xfc, 0xff, 0xc1, 0x03, 0xfc, 0xff, 0xc1, 0x03, 0xfc, 0x7f, 0xc0, 0x03, 
+  0x84, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 
+  0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 
+  0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 
+  0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xc0, 0x03, 
+  0x80, 0x07, 0xc0, 0x03, 0x80, 0x07, 0xe0, 0x07, 0x80, 0x07, 0xf0, 0x0f, 
+  0x80, 0x07, 0x70, 0x0e, 0x80, 0x07, 0x30, 0x0c, 0x80, 0x07, 0x30, 0x0c, 
+  0x80, 0x07, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x38, 0x27, 0xba, 0x1c, 
+  0x84, 0x68, 0x8a, 0x02, 0x84, 0xa8, 0xba, 0x32, 0x84, 0x28, 0x8b, 0x22, 
+  0x38, 0x27, 0x8a, 0x1c, 0x00, 0x00, 0x00, 0x00
+  };
diff --git a/tools/ioemu/gui/bitmaps/configbutton.xpm b/tools/ioemu/gui/bitmaps/configbutton.xpm
new file mode 100644 (file)
index 0000000..ef2f933
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *configbutton_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"..#....................##.......",
+"..#############.......####......",
+"..###############.....####......",
+"..###############.....####......",
+"..#############.......####......",
+"..#....####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####...........####......",
+".......####..........######.....",
+".......####.........########....",
+".......####.........###..###....",
+".......####.........##....##....",
+".......####.........##....##....",
+".......####..........#....#.....",
+"................................",
+"...###..###..#...#.###.#..###...",
+"..#....#...#.##..#.#...#.#......",
+"..#....#...#.#.#.#.###.#.#..##..",
+"..#....#...#.#..##.#...#.#...#..",
+"...###..###..#...#.#...#..###...",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/copy.h b/tools/ioemu/gui/bitmaps/copy.h
new file mode 100644 (file)
index 0000000..78546c9
--- /dev/null
@@ -0,0 +1,18 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: copy.h,v 1.1 2002/03/11 15:04:58 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_COPY_BMAP_X 32
+#define BX_COPY_BMAP_Y 32
+
+static unsigned char bx_copy_bmap[(BX_COPY_BMAP_X*BX_COPY_BMAP_Y)] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+  0x80, 0x60, 0x4e, 0x02, 0x80, 0x90, 0x52, 0x02, 0x80, 0x90, 0x52, 0x02,
+  0x00, 0x6f, 0x8e, 0x03, 0x00, 0x00, 0x02, 0x02, 0xf8, 0x3f, 0x02, 0x02,
+  0x08, 0x20, 0xc0, 0x01, 0xe8, 0x2b, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00,
+  0xe8, 0x2e, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0xe8, 0x39, 0x00, 0x00,
+  0x08, 0x24, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0xe8, 0xaf, 0xff, 0x03,
+  0x08, 0xa0, 0x00, 0x02, 0xf8, 0xbf, 0xbe, 0x02, 0x00, 0x80, 0x00, 0x02,
+  0x80, 0x88, 0xee, 0x02, 0x80, 0x90, 0x00, 0x02, 0x00, 0xbf, 0x9e, 0x03,
+  0x00, 0x90, 0x40, 0x02, 0x00, 0x88, 0x08, 0x02, 0x00, 0x80, 0xfe, 0x02,
+  0x00, 0x80, 0x00, 0x02, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/bitmaps/copy.xpm b/tools/ioemu/gui/bitmaps/copy.xpm
new file mode 100644 (file)
index 0000000..5e0138e
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *copy_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"........####....................",
+".......#........................",
+".......#.....##..###..#..#......",
+".......#....#..#.#..#.#..#......",
+".......#....#..#.#..#.#..#......",
+"........####.##..###...###......",
+".................#.......#......",
+"...###########...#.......#......",
+"...#.........#........###.......",
+"...#.#####.#.#..................",
+"...#.........#..................",
+"...#.###.###.#..................",
+"...#.........#..................",
+"...#.####..###..................",
+"...#......#..#..................",
+"...#...#.....#..................",
+"...#.#######.#.###########......",
+"...#.........#.#.........#......",
+"...###########.#.#####.#.#......",
+"...............#.........#......",
+".......#...#...#.###.###.#......",
+".......#....#..#.........#......",
+"........######.#.####..###......",
+"............#..#......#..#......",
+"...........#...#...#.....#......",
+"...............#.#######.#......",
+"...............#.........#......",
+"...............###########......",
+"................................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/floppya.h b/tools/ioemu/gui/bitmaps/floppya.h
new file mode 100644 (file)
index 0000000..86ba90f
--- /dev/null
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppya.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_FLOPPYA_BMAP_X 32
+#define BX_FLOPPYA_BMAP_Y 32
+
+static const unsigned char bx_floppya_bmap[(BX_FLOPPYA_BMAP_X * BX_FLOPPYA_BMAP_Y)/8] = {
+   0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x40, 0x11, 0x00,
+   0x00, 0xc0, 0x01, 0x00, 0x00, 0x60, 0x13, 0x00, 0x00, 0x60, 0x03, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0x20, 0xfd, 0xbf, 0x04, 0x20, 0x01, 0x80, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+   0xe0, 0xef, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07, 0xc0, 0xef, 0xea, 0x07,
+   0x80, 0x57, 0xd5, 0x07, 0x00, 0xaf, 0xea, 0x07
+  };
+
+static const unsigned char bx_floppya_eject_bmap[(BX_FLOPPYA_BMAP_X * BX_FLOPPYA_BMAP_Y)/8] = {
+   0x01, 0x80, 0x00, 0x80, 0x02, 0x40, 0x01, 0x40, 0x04, 0x40, 0x11, 0x20,
+   0x08, 0xc0, 0x01, 0x10, 0x10, 0x60, 0x13, 0x08, 0x20, 0x60, 0x03, 0x04,
+   0x40, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0x20, 0xff, 0xff, 0x04, 0x20, 0x05, 0xa0, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x11, 0x88, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x41, 0x82, 0x07,
+   0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x81, 0x81, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x21, 0x84, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x09, 0x90, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+   0xf0, 0xef, 0xea, 0x0f, 0xe8, 0xf7, 0xd5, 0x17, 0xc4, 0xef, 0xea, 0x27,
+   0x82, 0x57, 0xd5, 0x47, 0x01, 0xaf, 0xea, 0x87
+  };
diff --git a/tools/ioemu/gui/bitmaps/floppya.xpm b/tools/ioemu/gui/bitmaps/floppya.xpm
new file mode 100644 (file)
index 0000000..637f198
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *floppya_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"...............#................",
+"..............#.#...............",
+"..............#.#...#...........",
+"..............###...............",
+".............##.##..#...........",
+".............##.##..............",
+"................................",
+".....######################.....",
+".....####..............####.....",
+".....#..#.############.#..#.....",
+".....#..#..............#..#.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....#######.#.#.#.#.######.....",
+".....######.#####.#.#.#####.....",
+".....#######.###.#.#.######.....",
+".....######.#####.#.#.#####.....",
+"......######.###.#.#.######.....",
+".......####.#.#.#.#.#.#####.....",
+"........####.#.#.#.#.######....."
+};
diff --git a/tools/ioemu/gui/bitmaps/floppyb.h b/tools/ioemu/gui/bitmaps/floppyb.h
new file mode 100644 (file)
index 0000000..70c7597
--- /dev/null
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppyb.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_FLOPPYB_BMAP_X 32
+#define BX_FLOPPYB_BMAP_Y 32
+
+static const unsigned char bx_floppyb_bmap[(BX_FLOPPYB_BMAP_X * BX_FLOPPYB_BMAP_Y)/8] = {
+   0x00, 0xe0, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0xe0, 0x08, 0x00,
+   0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0xe0, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0x20, 0xfd, 0xbf, 0x04, 0x20, 0x01, 0x80, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x01, 0x80, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+   0xe0, 0xef, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07, 0xc0, 0xef, 0xea, 0x07,
+   0x80, 0x57, 0xd5, 0x07, 0x00, 0xaf, 0xea, 0x07
+  };
+
+static const unsigned char bx_floppyb_eject_bmap[(BX_FLOPPYB_BMAP_X * BX_FLOPPYB_BMAP_Y)/8] = {
+   0x01, 0xe0, 0x00, 0x80, 0x02, 0x20, 0x01, 0x40, 0x04, 0xe0, 0x08, 0x20,
+   0x08, 0x20, 0x01, 0x10, 0x10, 0x20, 0x09, 0x08, 0x20, 0xe0, 0x00, 0x04,
+   0x40, 0x00, 0x00, 0x02, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0x01, 0x80, 0x07,
+   0x20, 0xff, 0xff, 0x04, 0x20, 0x05, 0xa0, 0x04, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x11, 0x88, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x41, 0x82, 0x07,
+   0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x81, 0x81, 0x07, 0xe0, 0xfd, 0xbf, 0x07,
+   0xe0, 0x21, 0x84, 0x07, 0xe0, 0xfd, 0xbf, 0x07, 0xe0, 0x09, 0x90, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07,
+   0xe0, 0xff, 0xff, 0x07, 0xe0, 0xaf, 0xea, 0x07, 0xe0, 0xf7, 0xd5, 0x07,
+   0xf0, 0xef, 0xea, 0x0f, 0xe8, 0xf7, 0xd5, 0x17, 0xc4, 0xef, 0xea, 0x27,
+   0x82, 0x57, 0xd5, 0x47, 0x01, 0xaf, 0xea, 0x87
+  };
diff --git a/tools/ioemu/gui/bitmaps/floppyb.xpm b/tools/ioemu/gui/bitmaps/floppyb.xpm
new file mode 100644 (file)
index 0000000..f4e20e5
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *floppyb_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+".............###................",
+".............#..#...............",
+".............###...#............",
+".............#..#...............",
+".............#..#..#............",
+".............###................",
+"................................",
+".....######################.....",
+".....####..............####.....",
+".....#..#.############.#..#.....",
+".....#..#..............#..#.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....####.############.####.....",
+".....####..............####.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....######################.....",
+".....#######.#.#.#.#.######.....",
+".....######.#####.#.#.#####.....",
+".....#######.###.#.#.######.....",
+".....######.#####.#.#.#####.....",
+"......######.###.#.#.######.....",
+".......####.#.#.#.#.#.#####.....",
+"........####.#.#.#.#.######....."
+};
diff --git a/tools/ioemu/gui/bitmaps/mouse.h b/tools/ioemu/gui/bitmaps/mouse.h
new file mode 100644 (file)
index 0000000..cc8f364
--- /dev/null
@@ -0,0 +1,34 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: mouse.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_MOUSE_BMAP_X 32
+#define BX_MOUSE_BMAP_Y 32
+
+static unsigned char bx_mouse_bmap[(BX_MOUSE_BMAP_X * BX_MOUSE_BMAP_Y)/8] = {
+   0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf8, 0x1f, 0x00,
+   0x00, 0x0c, 0x30, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x40, 0x00,
+   0xf8, 0xff, 0xc0, 0x00, 0x0c, 0x80, 0xc1, 0x00, 0x24, 0x22, 0xc1, 0x00,
+   0x74, 0x77, 0x81, 0x00, 0x74, 0x77, 0x81, 0x01, 0x74, 0x77, 0x81, 0x01,
+   0x74, 0x77, 0x01, 0x01, 0x74, 0x77, 0x01, 0x03, 0x74, 0x77, 0x01, 0x06,
+   0x24, 0x22, 0x01, 0x0c, 0x0c, 0x80, 0x01, 0x38, 0x04, 0x00, 0x01, 0x00,
+   0x0c, 0x80, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x80, 0x01, 0x00,
+   0x04, 0x00, 0x01, 0x00, 0x0c, 0x80, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+   0x0c, 0x80, 0x01, 0x00, 0x14, 0x40, 0x01, 0x00, 0x2c, 0xa0, 0x01, 0x00,
+   0x54, 0x55, 0x01, 0x00, 0xac, 0xaa, 0x01, 0x00, 0xf8, 0xff, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+   };
+
+static unsigned char bx_nomouse_bmap[(BX_MOUSE_BMAP_X * BX_MOUSE_BMAP_Y)/8] = {
+   0x01, 0x00, 0x00, 0x80, 0x02, 0xe0, 0x07, 0x40, 0x04, 0xf8, 0x1f, 0x20,
+   0x08, 0x0c, 0x30, 0x10, 0x10, 0x06, 0x60, 0x08, 0x20, 0x06, 0x40, 0x04,
+   0xf8, 0xff, 0xc0, 0x02, 0x8c, 0x80, 0xc1, 0x01, 0x24, 0x23, 0xc1, 0x00,
+   0x74, 0x77, 0xc1, 0x00, 0x74, 0x77, 0xa1, 0x01, 0x74, 0x7f, 0x91, 0x01,
+   0x74, 0x77, 0x09, 0x01, 0x74, 0x77, 0x05, 0x03, 0x74, 0x77, 0x03, 0x06,
+   0x24, 0xa2, 0x01, 0x0c, 0x0c, 0x80, 0x01, 0x38, 0x04, 0x40, 0x03, 0x00,
+   0x0c, 0xa0, 0x05, 0x00, 0x04, 0x10, 0x09, 0x00, 0x0c, 0x88, 0x11, 0x00,
+   0x04, 0x04, 0x21, 0x00, 0x0c, 0x82, 0x41, 0x00, 0x04, 0x01, 0x81, 0x00,
+   0x8c, 0x80, 0x01, 0x01, 0x54, 0x40, 0x01, 0x02, 0x2c, 0xa0, 0x01, 0x04,
+   0x54, 0x55, 0x01, 0x08, 0xac, 0xaa, 0x01, 0x10, 0xfc, 0xff, 0x00, 0x20,
+   0x02, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x80
+   };
diff --git a/tools/ioemu/gui/bitmaps/mouse.xpm b/tools/ioemu/gui/bitmaps/mouse.xpm
new file mode 100644 (file)
index 0000000..dea3327
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *mouse_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............######.............",
+"...........##########...........",
+"..........##........##..........",
+".........##..........##.........",
+".........##...........#.........",
+"...#############......##........",
+"..##...........##.....##........",
+"..#..#...#...#..#.....##........",
+"..#.###.###.###.#......#........",
+"..#.###.###.###.#......##.......",
+"..#.###.###.###.#......##.......",
+"..#.###.###.###.#.......#.......",
+"..#.###.###.###.#.......##......",
+"..#.###.###.###.#........##.....",
+"..#..#...#...#..#.........##....",
+"..##...........##..........###..",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.............#...............",
+"..##...........##...............",
+"..#.#.........#.#...............",
+"..##.#.......#.##...............",
+"..#.#.#.#.#.#.#.#...............",
+"..##.#.#.#.#.#.##...............",
+"...#############................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/paste.h b/tools/ioemu/gui/bitmaps/paste.h
new file mode 100644 (file)
index 0000000..f574dad
--- /dev/null
@@ -0,0 +1,18 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: paste.h,v 1.1 2002/03/11 15:04:58 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_PASTE_BMAP_X 32
+#define BX_PASTE_BMAP_Y 32
+
+static unsigned char bx_paste_bmap[(BX_PASTE_BMAP_X*BX_PASTE_BMAP_Y)] = {
+  0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x10, 0x00, 0x20, 0x9a, 0x93, 0x03,
+  0x20, 0x66, 0x78, 0x04, 0xe0, 0xa5, 0xd3, 0x07, 0x20, 0x24, 0x54, 0x00,
+  0x20, 0xd8, 0x93, 0x03, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x02, 0x00,
+  0x00, 0x7c, 0x3f, 0x00, 0xc0, 0x83, 0xc1, 0x03, 0x20, 0x02, 0x40, 0x04,
+  0x20, 0x01, 0x80, 0x04, 0x20, 0x01, 0x80, 0x04, 0xa0, 0xff, 0xff, 0x05,
+  0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x20, 0xf8, 0x3f, 0x04,
+  0x20, 0x08, 0x20, 0x04, 0x20, 0xe8, 0x2b, 0x04, 0x20, 0x08, 0x20, 0x04,
+  0x20, 0xe8, 0x2e, 0x04, 0x20, 0x08, 0x20, 0x04, 0x20, 0xe8, 0x39, 0x04,
+  0x20, 0x08, 0x24, 0x04, 0x20, 0x88, 0x20, 0x04, 0x20, 0xe8, 0x2f, 0x04,
+  0x20, 0x08, 0x20, 0x04, 0x20, 0xf8, 0x3f, 0x04, 0x20, 0x00, 0x00, 0x04,
+  0xc0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/bitmaps/paste.xpm b/tools/ioemu/gui/bitmaps/paste.xpm
new file mode 100644 (file)
index 0000000..5c83b01
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *paste_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".....####...........#...........",
+".....#...#.##..###..#..###......",
+".....#...##..##....####...#.....",
+".....####.#..#.###..#.#####.....",
+".....#....#..#....#.#.#.........",
+".....#.....##.####..#..###......",
+"...............##...............",
+"..............##.#..............",
+"..........#####.######..........",
+"......####.....##.....####......",
+".....#...#............#...#.....",
+".....#..#..............#..#.....",
+".....#..#..............#..#.....",
+".....#.##################.#.....",
+".....#....................#.....",
+".....#....................#.....",
+".....#.....###########....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.#####.#.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.###.###.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....#.####..###....#.....",
+".....#.....#......#..#....#.....",
+".....#.....#...#.....#....#.....",
+".....#.....#.#######.#....#.....",
+".....#.....#.........#....#.....",
+".....#.....###########....#.....",
+".....#....................#.....",
+"......####################......",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/power.h b/tools/ioemu/gui/bitmaps/power.h
new file mode 100644 (file)
index 0000000..ba72d6a
--- /dev/null
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: power.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_POWER_BMAP_X 32
+#define BX_POWER_BMAP_Y 32
+
+static const unsigned char bx_power_bmap[(BX_POWER_BMAP_X * BX_POWER_BMAP_Y)/8] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
+  0x24, 0x67, 0x66, 0x34, 0xa4, 0x28, 0x92, 0x48, 0x9a, 0xa8, 0xfa, 0x04,
+  0x82, 0x64, 0x09, 0x04, 0x07, 0xa3, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0xf8, 0x03, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x0f, 0x1e, 0x00,
+  0x80, 0x03, 0x38, 0x00, 0xc0, 0x00, 0x60, 0x00, 0xe0, 0xe0, 0xe0, 0x00,
+  0x60, 0xe0, 0xc0, 0x00, 0x70, 0xe0, 0xc0, 0x01, 0x30, 0xe0, 0x80, 0x01,
+  0x30, 0xe0, 0x80, 0x01, 0x30, 0xe0, 0x80, 0x01, 0x30, 0xe0, 0x80, 0x01,
+  0x30, 0xe0, 0x80, 0x01, 0x70, 0xe0, 0xc0, 0x01, 0x60, 0xe0, 0xc0, 0x00,
+  0xe0, 0xe0, 0xe0, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x80, 0x03, 0x38, 0x00,
+  0x00, 0x0f, 0x1e, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xf8, 0x03, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
diff --git a/tools/ioemu/gui/bitmaps/power.xpm b/tools/ioemu/gui/bitmaps/power.xpm
new file mode 100644 (file)
index 0000000..ff7e9e8
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *power_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"................................",
+".####...........................",
+"..#..#..###..##..##..##...#.##..",
+"..#..#.#...#.#...#..#..#...#..#.",
+".#.##..#...#.#.#.#.#####..#.....",
+".#.....#..#..##.#..#......#.....",
+"###.....##...#.#....###..###....",
+"................................",
+"...........#######..............",
+".........###########............",
+"........####.....####...........",
+".......###.........###..........",
+"......##.............##.........",
+".....###.....###.....###........",
+".....##......###......##........",
+"....###......###......###.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....##.......###.......##.......",
+"....###......###......###.......",
+".....##......###......##........",
+".....###.....###.....###........",
+"......##.............##.........",
+".......###.........###..........",
+"........####.....####...........",
+".........###########............",
+"...........#######..............",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/reset.h b/tools/ioemu/gui/bitmaps/reset.h
new file mode 100644 (file)
index 0000000..046f80a
--- /dev/null
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: reset.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_RESET_BMAP_X 32
+#define BX_RESET_BMAP_Y 32
+
+static const unsigned char bx_reset_bmap[(BX_RESET_BMAP_X * BX_RESET_BMAP_Y)/8] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3c, 0x00, 0x00, 0x10,
+  0x48, 0x0c, 0xc7, 0x7c, 0x48, 0x92, 0x20, 0x11, 0x34, 0x1f, 0xf3, 0x09,
+  0x24, 0x41, 0x12, 0x48, 0x6e, 0xce, 0xe1, 0x30, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
+  0x00, 0xe0, 0x0f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xe0, 0x3f, 0x00,
+  0x00, 0xc7, 0x38, 0x00, 0x00, 0x87, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00,
+  0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x38, 0x00,
+  0x00, 0x07, 0x38, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x1f, 0x00,
+  0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
diff --git a/tools/ioemu/gui/bitmaps/reset.xpm b/tools/ioemu/gui/bitmaps/reset.xpm
new file mode 100644 (file)
index 0000000..d47ea6c
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *reset_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+".............................#..",
+"..####......................#...",
+"...#..#...##....###...##..#####.",
+"...#..#..#..#..#.....#..#...#...",
+"..#.##..#####...##..#####..#....",
+"..#..#..#.....#..#..#......#..#.",
+".###.##..###..###....###....##..",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................",
+"...............#................",
+"..............##................",
+".............#######............",
+"............#########...........",
+".............#########..........",
+"........###...##...###..........",
+"........###....#...###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........###........###..........",
+"........##############..........",
+".........############...........",
+"..........##########............",
+"................................",
+"................................",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/bitmaps/snapshot.h b/tools/ioemu/gui/bitmaps/snapshot.h
new file mode 100644 (file)
index 0000000..cced8ff
--- /dev/null
@@ -0,0 +1,20 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: snapshot.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#define BX_SNAPSHOT_BMAP_X 32
+#define BX_SNAPSHOT_BMAP_Y 32
+
+static const unsigned char bx_snapshot_bmap[(BX_SNAPSHOT_BMAP_X * BX_SNAPSHOT_BMAP_Y)/8] = {
+  0x00, 0x00, 0x20, 0x40, 0x77, 0xe6, 0xee, 0xec, 0x91, 0xa8, 0xa2, 0x52,
+  0x96, 0xac, 0xac, 0x52, 0x94, 0xaa, 0xa8, 0x52, 0xb7, 0xee, 0xae, 0xcc,
+  0x00, 0x20, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x08, 0x10, 0x00,
+  0x7c, 0x0f, 0x10, 0x1f, 0xfa, 0x07, 0xa0, 0x2e, 0x42, 0x07, 0xa0, 0x50,
+  0xa3, 0x03, 0xc0, 0xe0, 0xff, 0xee, 0x77, 0xbf, 0x01, 0xf9, 0x9f, 0x40,
+  0x01, 0x1d, 0xb8, 0xa0, 0xff, 0xe5, 0xa7, 0xff, 0xff, 0xba, 0x5a, 0xff,
+  0xff, 0x55, 0xb5, 0xff, 0xff, 0x8d, 0xaa, 0xff, 0xff, 0x16, 0x55, 0xff,
+  0xff, 0xa2, 0x6a, 0xff, 0xff, 0x46, 0x55, 0xff, 0xff, 0xaa, 0x6a, 0xff,
+  0xff, 0x56, 0x55, 0xff, 0xfe, 0xae, 0x6a, 0x7f, 0x00, 0x55, 0xb5, 0x00,
+  0x00, 0xbd, 0xba, 0x00, 0x00, 0xfa, 0x5f, 0x00, 0x00, 0xe4, 0x27, 0x00,
+  0x00, 0x18, 0x18, 0x00, 0x00, 0xe0, 0x07, 0x00
+  };
diff --git a/tools/ioemu/gui/bitmaps/snapshot.xpm b/tools/ioemu/gui/bitmaps/snapshot.xpm
new file mode 100644 (file)
index 0000000..c17305b
--- /dev/null
@@ -0,0 +1,41 @@
+/* XPM */
+static char *snapshot_xpm[] = {
+/* width height num_colors chars_per_pixel */
+"    32    32        2            1",
+/* colors */
+". c None",
+"# c #000000",
+/* pixels */
+".....................#........#.",
+"###.###..##..###.###.###..##.###",
+"#...#..#...#.#.#.#...#.#.#..#.#.",
+".##.#..#..##.#.#..##.#.#.#..#.#.",
+"..#.#..#.#.#.#.#...#.#.#.#..#.#.",
+"###.##.#.###.###.###.#.#..##..##",
+".............#..................",
+"............########............",
+"...........#........#...........",
+"..#####.####........#...#####...",
+".#.########..........#.#.###.#..",
+".#....#.###..........#.#....#.#.",
+"##...#.###............##.....###",
+"########.###.######.###.######.#",
+"#.......#..##########..#......#.",
+"#.......#.###......###.#.....#.#",
+"#########.#..######..#.#########",
+"########.#.###.#.#.##.#.########",
+"#########.#.#.#.#.#.##.#########",
+"#########.##...#.#.#.#.#########",
+"########.##.#...#.#.#.#.########",
+"########.#...#.#.#.#.##.########",
+"########.##...#.#.#.#.#.########",
+"########.#.#.#.#.#.#.##.########",
+"########.##.#.#.#.#.#.#.########",
+".#######.###.#.#.#.#.##.#######.",
+"........#.#.#.#.#.#.##.#........",
+"........#.####.#.#.###.#........",
+".........#.##########.#.........",
+"..........#..######..#..........",
+"...........##......##...........",
+".............######............."
+};
diff --git a/tools/ioemu/gui/bitmaps/userbutton.h b/tools/ioemu/gui/bitmaps/userbutton.h
new file mode 100644 (file)
index 0000000..c93f506
--- /dev/null
@@ -0,0 +1,19 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: userbutton.h,v 1.1 2002/08/09 06:16:43 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+#define BX_USER_BMAP_X 32
+#define BX_USER_BMAP_Y 32
+
+static const unsigned char bx_user_bmap[BX_USER_BMAP_X*BX_USER_BMAP_Y/8] = {
+  0x00, 0x00, 0x00, 0x00, 0x84, 0x78, 0x9e, 0x07, 0x84, 0x04, 0x82, 0x08, 
+  0x84, 0x04, 0x82, 0x08, 0x84, 0x38, 0x9e, 0x07, 0x84, 0x40, 0x82, 0x01, 
+  0x84, 0x40, 0x82, 0x06, 0x78, 0x3c, 0x9e, 0x08, 0x00, 0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1c, 
+  0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 
+  0x00, 0x00, 0x80, 0x00, 0xfe, 0xff, 0xff, 0x3f, 0x02, 0x00, 0x00, 0x20, 
+  0xaa, 0xaa, 0x2a, 0x2a, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 
+  0xaa, 0xaa, 0xaa, 0x2a, 0x52, 0x55, 0x11, 0x25, 0xaa, 0xaa, 0xaa, 0x2a, 
+  0x52, 0x55, 0x01, 0x25, 0xaa, 0xaa, 0x82, 0x2a, 0x52, 0x55, 0x11, 0x25, 
+  0xaa, 0xbf, 0xaa, 0x2a, 0x02, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x3f, 
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
diff --git a/tools/ioemu/gui/bitmaps/userbutton.xpm b/tools/ioemu/gui/bitmaps/userbutton.xpm
new file mode 100644 (file)
index 0000000..a5d1f99
--- /dev/null
@@ -0,0 +1,40 @@
+/* XPM */
+static char *userbutton_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 2 1",
+". c None",
+"# c #000000",
+/* pixels */
+"................................",
+"..#....#...####..####..####.....",
+"..#....#..#......#.....#...#....",
+"..#....#..#......#.....#...#....",
+"..#....#...###...####..####.....",
+"..#....#......#..#.....##.......",
+"..#....#......#..#.....#.##.....",
+"...####...####...####..#...#....",
+"................................",
+"................................",
+".............................#..",
+"..........................###...",
+".........................#......",
+"........................#.......",
+".......................#........",
+".......................#........",
+".#############################..",
+".#...........................#..",
+".#.#.#.#.#.#.#.#.#.#.#...#.#.#..",
+".#...........................#..",
+".#...........................#..",
+".#.#.#.#.#.#.#.#.#.#.#.#.#.#.#..",
+".#..#.#.#.#.#.#.#...#...#.#..#..",
+".#.#.#.#.#.#.#.#.#.#.#.#.#.#.#..",
+".#..#.#.#.#.#.#.#.......#.#..#..",
+".#.#.#.#.#.#.#.#.#.....#.#.#.#..",
+".#..#.#.#.#.#.#.#...#...#.#..#..",
+".#.#.#.#######.#.#.#.#.#.#.#.#..",
+".#...........................#..",
+".#############################..",
+"................................",
+"................................"
+};
diff --git a/tools/ioemu/gui/gui.cc b/tools/ioemu/gui/gui.cc
new file mode 100644 (file)
index 0000000..a6cd307
--- /dev/null
@@ -0,0 +1,592 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gui.cc,v 1.73 2003/12/18 20:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#include <signal.h>
+#include "bochs.h"
+#include "gui/bitmaps/floppya.h"
+#include "gui/bitmaps/floppyb.h"
+#include "gui/bitmaps/mouse.h"
+#include "gui/bitmaps/reset.h"
+#include "gui/bitmaps/power.h"
+#include "gui/bitmaps/snapshot.h"
+#include "gui/bitmaps/copy.h"
+#include "gui/bitmaps/paste.h"
+#include "gui/bitmaps/configbutton.h"
+#include "gui/bitmaps/cdromd.h"
+#include "gui/bitmaps/userbutton.h"
+#if BX_WITH_MACOS
+#  include <Disks.h>
+#endif
+
+bx_gui_c *bx_gui = NULL;
+
+#define BX_GUI_THIS bx_gui->
+#define LOG_THIS BX_GUI_THIS
+
+bx_gui_c::bx_gui_c(void)
+{
+  put("GUI"); // Init in specific_init
+  settype(GUILOG);
+}
+
+bx_gui_c::~bx_gui_c()
+{
+}
+
+  void
+bx_gui_c::init(int argc, char **argv, unsigned tilewidth, unsigned tileheight)
+{
+  specific_init(argc, argv, tilewidth, tileheight, BX_HEADER_BAR_Y);
+
+  // Define some bitmaps to use in the headerbar
+  BX_GUI_THIS floppyA_bmap_id = create_bitmap(bx_floppya_bmap,
+                          BX_FLOPPYA_BMAP_X, BX_FLOPPYA_BMAP_Y);
+  BX_GUI_THIS floppyA_eject_bmap_id = create_bitmap(bx_floppya_eject_bmap,
+                          BX_FLOPPYA_BMAP_X, BX_FLOPPYA_BMAP_Y);
+  BX_GUI_THIS floppyB_bmap_id = create_bitmap(bx_floppyb_bmap,
+                          BX_FLOPPYB_BMAP_X, BX_FLOPPYB_BMAP_Y);
+  BX_GUI_THIS floppyB_eject_bmap_id = create_bitmap(bx_floppyb_eject_bmap,
+                          BX_FLOPPYB_BMAP_X, BX_FLOPPYB_BMAP_Y);
+  BX_GUI_THIS cdromD_bmap_id = create_bitmap(bx_cdromd_bmap,
+                          BX_CDROMD_BMAP_X, BX_CDROMD_BMAP_Y);
+  BX_GUI_THIS cdromD_eject_bmap_id = create_bitmap(bx_cdromd_eject_bmap,
+                          BX_CDROMD_BMAP_X, BX_CDROMD_BMAP_Y);
+  BX_GUI_THIS mouse_bmap_id = create_bitmap(bx_mouse_bmap,
+                          BX_MOUSE_BMAP_X, BX_MOUSE_BMAP_Y);
+  BX_GUI_THIS nomouse_bmap_id = create_bitmap(bx_nomouse_bmap,
+                          BX_MOUSE_BMAP_X, BX_MOUSE_BMAP_Y);
+
+
+  BX_GUI_THIS power_bmap_id = create_bitmap(bx_power_bmap, BX_POWER_BMAP_X, BX_POWER_BMAP_Y);
+  BX_GUI_THIS reset_bmap_id = create_bitmap(bx_reset_bmap, BX_RESET_BMAP_X, BX_RESET_BMAP_Y);
+  BX_GUI_THIS snapshot_bmap_id = create_bitmap(bx_snapshot_bmap, BX_SNAPSHOT_BMAP_X, BX_SNAPSHOT_BMAP_Y);
+  BX_GUI_THIS copy_bmap_id = create_bitmap(bx_copy_bmap, BX_COPY_BMAP_X, BX_COPY_BMAP_Y);
+  BX_GUI_THIS paste_bmap_id = create_bitmap(bx_paste_bmap, BX_PASTE_BMAP_X, BX_PASTE_BMAP_Y);
+  BX_GUI_THIS config_bmap_id = create_bitmap(bx_config_bmap, BX_CONFIG_BMAP_X, BX_CONFIG_BMAP_Y);
+  BX_GUI_THIS user_bmap_id = create_bitmap(bx_user_bmap, BX_USER_BMAP_X, BX_USER_BMAP_Y);
+
+
+  // Add the initial bitmaps to the headerbar, and enable callback routine, for use
+  // when that bitmap is clicked on
+
+  // Floppy A:
+  BX_GUI_THIS floppyA_status = DEV_floppy_get_media_status(0);
+  if (BX_GUI_THIS floppyA_status)
+    BX_GUI_THIS floppyA_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyA_bmap_id,
+                          BX_GRAVITY_LEFT, floppyA_handler);
+  else
+    BX_GUI_THIS floppyA_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyA_eject_bmap_id,
+                          BX_GRAVITY_LEFT, floppyA_handler);
+
+  // Floppy B:
+  BX_GUI_THIS floppyB_status = DEV_floppy_get_media_status(1);
+  if (BX_GUI_THIS floppyB_status)
+    BX_GUI_THIS floppyB_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyB_bmap_id,
+                          BX_GRAVITY_LEFT, floppyB_handler);
+  else
+    BX_GUI_THIS floppyB_hbar_id = headerbar_bitmap(BX_GUI_THIS floppyB_eject_bmap_id,
+                          BX_GRAVITY_LEFT, floppyB_handler);
+
+  // CDROM, 
+  // valgrinds says that the harddrive object is not be initialised yet, 
+  // so we just set the bitmap to ejected for now
+#if 0
+  if (DEV_hd_present()) {
+    Bit32u handle = DEV_hd_get_first_cd_handle();
+    BX_GUI_THIS cdromD_status = DEV_hd_get_cd_media_status(handle);
+  }
+
+  if (BX_GUI_THIS cdromD_status)
+    BX_GUI_THIS cdromD_hbar_id = headerbar_bitmap(BX_GUI_THIS cdromD_bmap_id,
+                          BX_GRAVITY_LEFT, cdromD_handler);
+  else
+#endif
+    BX_GUI_THIS cdromD_hbar_id = headerbar_bitmap(BX_GUI_THIS cdromD_eject_bmap_id,
+                          BX_GRAVITY_LEFT, cdromD_handler);
+
+  // Mouse button
+  if (bx_options.Omouse_enabled->get ())
+    BX_GUI_THIS mouse_hbar_id = headerbar_bitmap(BX_GUI_THIS mouse_bmap_id,
+                          BX_GRAVITY_LEFT, toggle_mouse_enable);
+  else
+    BX_GUI_THIS mouse_hbar_id = headerbar_bitmap(BX_GUI_THIS nomouse_bmap_id,
+                          BX_GRAVITY_LEFT, toggle_mouse_enable);
+
+  // These are the buttons on the right side.  They are created in order
+  // of right to left.
+
+  // Power button
+  BX_GUI_THIS power_hbar_id = headerbar_bitmap(BX_GUI_THIS power_bmap_id,
+                          BX_GRAVITY_RIGHT, power_handler);
+  // Reset button
+  BX_GUI_THIS reset_hbar_id = headerbar_bitmap(BX_GUI_THIS reset_bmap_id,
+                          BX_GRAVITY_RIGHT, reset_handler);
+  // Configure button
+  BX_GUI_THIS config_hbar_id = headerbar_bitmap(BX_GUI_THIS config_bmap_id,
+                          BX_GRAVITY_RIGHT, config_handler);
+  // Snapshot button
+  BX_GUI_THIS snapshot_hbar_id = headerbar_bitmap(BX_GUI_THIS snapshot_bmap_id,
+                          BX_GRAVITY_RIGHT, snapshot_handler);
+  // Paste button
+  BX_GUI_THIS paste_hbar_id = headerbar_bitmap(BX_GUI_THIS paste_bmap_id,
+                          BX_GRAVITY_RIGHT, paste_handler);
+  // Copy button
+  BX_GUI_THIS copy_hbar_id = headerbar_bitmap(BX_GUI_THIS copy_bmap_id,
+                          BX_GRAVITY_RIGHT, copy_handler);
+  // User button
+  BX_GUI_THIS user_hbar_id = headerbar_bitmap(BX_GUI_THIS user_bmap_id,
+                          BX_GRAVITY_RIGHT, userbutton_handler);
+
+  if(bx_options.Otext_snapshot_check->get()) {
+    bx_pc_system.register_timer(this, bx_gui_c::snapshot_checker, (unsigned) 1000000, 1, 1, "snap_chk");
+  }
+
+  BX_GUI_THIS charmap_updated = 0;
+
+  show_headerbar();
+}
+
+void
+bx_gui_c::update_drive_status_buttons (void) {
+  BX_GUI_THIS floppyA_status = 
+    DEV_floppy_get_media_status(0)
+    && bx_options.floppya.Ostatus->get ();
+  BX_GUI_THIS floppyB_status = 
+      DEV_floppy_get_media_status(1)
+      && bx_options.floppyb.Ostatus->get ();
+  Bit32u handle = DEV_hd_get_first_cd_handle();
+  BX_GUI_THIS cdromD_status = DEV_hd_get_cd_media_status(handle);
+  if (BX_GUI_THIS floppyA_status)
+    replace_bitmap(BX_GUI_THIS floppyA_hbar_id, BX_GUI_THIS floppyA_bmap_id);
+  else {
+#if BX_WITH_MACOS
+    // If we are using the Mac floppy driver, eject the disk
+    // from the floppy drive.  This doesn't work in MacOS X.
+    if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+      DiskEject(1);
+#endif
+    replace_bitmap(BX_GUI_THIS floppyA_hbar_id, BX_GUI_THIS floppyA_eject_bmap_id);
+    }
+  if (BX_GUI_THIS floppyB_status)
+    replace_bitmap(BX_GUI_THIS floppyB_hbar_id, BX_GUI_THIS floppyB_bmap_id);
+  else {
+#if BX_WITH_MACOS
+    // If we are using the Mac floppy driver, eject the disk
+    // from the floppy drive.  This doesn't work in MacOS X.
+    if (!strcmp(bx_options.floppyb.Opath->getptr (), SuperDrive))
+      DiskEject(1);
+#endif
+    replace_bitmap(BX_GUI_THIS floppyB_hbar_id, BX_GUI_THIS floppyB_eject_bmap_id);
+    }
+  if (BX_GUI_THIS cdromD_status)
+    replace_bitmap(BX_GUI_THIS cdromD_hbar_id, BX_GUI_THIS cdromD_bmap_id);
+  else {
+    replace_bitmap(BX_GUI_THIS cdromD_hbar_id, BX_GUI_THIS cdromD_eject_bmap_id);
+    }
+}
+
+  void
+bx_gui_c::floppyA_handler(void)
+{
+  if (bx_options.floppya.Odevtype->get() == BX_FLOPPY_NONE)
+    return; // no primary floppy device present
+#ifdef WIN32
+  if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+              "rfb")) {
+    // instead of just toggling the status, call win32dialog to bring up
+    // a dialog asking what disk image you want to switch to.
+    int ret = SIM->ask_param (BXP_FLOPPYA_PATH);
+    if (ret > 0) {
+      BX_GUI_THIS update_drive_status_buttons ();
+    }
+    return;
+  }
+#endif
+  BX_GUI_THIS floppyA_status = !BX_GUI_THIS floppyA_status;
+  DEV_floppy_set_media_status(0, BX_GUI_THIS floppyA_status);
+  BX_GUI_THIS update_drive_status_buttons ();
+}
+
+  void
+bx_gui_c::floppyB_handler(void)
+{
+  if (bx_options.floppyb.Odevtype->get() == BX_FLOPPY_NONE)
+    return; // no secondary floppy device present
+#ifdef WIN32
+  if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+              "rfb")) {
+    // instead of just toggling the status, call win32dialog to bring up
+    // a dialog asking what disk image you want to switch to.
+    int ret = SIM->ask_param (BXP_FLOPPYB_PATH);
+    if (ret > 0) {
+      BX_GUI_THIS update_drive_status_buttons ();
+    }
+    return;
+  }
+#endif
+  BX_GUI_THIS floppyB_status = !BX_GUI_THIS floppyB_status;
+  DEV_floppy_set_media_status(1, BX_GUI_THIS floppyB_status);
+  BX_GUI_THIS update_drive_status_buttons ();
+}
+
+  void
+bx_gui_c::cdromD_handler(void)
+{
+  Bit32u handle = DEV_hd_get_first_cd_handle();
+  if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+              "wx")) {
+    // instead of just toggling the status, call wxWindows to bring up 
+    // a dialog asking what disk image you want to switch to.
+    // BBD: for now, find the first cdrom and call ask_param on that.
+    // Since we could have multiple cdroms now, maybe we should be adding
+    // one cdrom button for each?
+    bx_param_c *cdrom = SIM->get_first_cdrom ();
+    if (cdrom == NULL)
+      return;  // no cdrom found
+    int ret = SIM->ask_param (cdrom->get_id ());
+    if (ret < 0) return;  // cancelled
+    // eject and then insert the disk.  If the new path is invalid,
+    // the status will return 0.
+    unsigned status = DEV_hd_set_cd_media_status(handle, 0);
+    printf ("eject disk, new_status is %d\n", status);
+    status = DEV_hd_set_cd_media_status(handle, 1);
+    printf ("insert disk, new_status is %d\n", status);
+    fflush (stdout);
+    BX_GUI_THIS cdromD_status = status;
+  } else {
+    BX_GUI_THIS cdromD_status =
+      DEV_hd_set_cd_media_status(handle, !BX_GUI_THIS cdromD_status);
+  }
+  BX_GUI_THIS update_drive_status_buttons ();
+}
+
+  void
+bx_gui_c::reset_handler(void)
+{
+  BX_INFO(( "system RESET callback." ));
+  bx_pc_system.ResetSignal( PCS_SET ); /* XXX is this right? */
+  for (int i=0; i<BX_SMP_PROCESSORS; i++)
+      BX_CPU(i)->reset(BX_RESET_HARDWARE);
+}
+
+  void
+bx_gui_c::power_handler(void)
+{
+  // the user pressed power button, so there's no doubt they want bochs
+  // to quit.  Change panics to fatal for the GUI and then do a panic.
+  bx_user_quit = 1;
+  LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+  BX_PANIC (("POWER button turned off."));
+  // shouldn't reach this point, but if you do, QUIT!!!
+  fprintf (stderr, "Bochs is exiting because you pressed the power button.\n");
+  BX_EXIT (1);
+}
+
+Bit32s
+bx_gui_c::make_text_snapshot (char **snapshot, Bit32u *length)
+{
+  Bit8u* raw_snap = NULL;
+  char *clean_snap;
+  unsigned line_addr, txt_addr, txHeight, txWidth;
+
+  DEV_vga_get_text_snapshot(&raw_snap, &txHeight, &txWidth);
+  if (txHeight <= 0) return -1;
+  clean_snap = (char*) malloc(txHeight*(txWidth+2)+1);
+  txt_addr = 0;
+  for (unsigned i=0; i<txHeight; i++) {
+    line_addr = i * txWidth * 2;
+    for (unsigned j=0; j<(txWidth*2); j+=2) {
+      clean_snap[txt_addr++] = raw_snap[line_addr+j];
+    }
+    while ((txt_addr > 0) && (clean_snap[txt_addr-1] == ' ')) txt_addr--;
+#ifdef WIN32
+    if(!(bx_options.Otext_snapshot_check->get())) {
+      clean_snap[txt_addr++] = 13;
+    }
+#endif
+    clean_snap[txt_addr++] = 10;
+  }
+  clean_snap[txt_addr] = 0;
+  *snapshot = clean_snap;
+  *length = txt_addr;
+  return 0;
+}
+
+// create a text snapshot and copy to the system clipboard.  On guis that
+// we haven't figured out how to support yet, dump to a file instead.
+  void
+bx_gui_c::copy_handler(void)
+{
+  Bit32u len;
+  char *text_snapshot;
+  if (make_text_snapshot (&text_snapshot, &len) < 0) {
+    BX_INFO(( "copy button failed, mode not implemented"));
+    return;
+  }
+  if (!BX_GUI_THIS set_clipboard_text(text_snapshot, len)) {
+    // platform specific code failed, use portable code instead
+    FILE *fp = fopen("copy.txt", "w");
+    fwrite(text_snapshot, 1, len, fp);
+    fclose(fp);
+  }
+  free(text_snapshot);
+}
+
+// Check the current text snapshot against file snapchk.txt.
+  void
+bx_gui_c::snapshot_checker(void * this_ptr)
+{
+  char filename[BX_PATHNAME_LEN];
+  strcpy(filename,"snapchk.txt");
+  FILE *fp = fopen(filename, "rb");
+  if(fp) {
+    char *text_snapshot;
+    Bit32u len;
+    if (make_text_snapshot (&text_snapshot, &len) < 0) {
+      return;
+    }
+    char *compare_snapshot = (char *) malloc((len+1) * sizeof(char));
+    fread(compare_snapshot, 1, len, fp);
+    fclose(fp);
+    strcpy(filename,"snapmask.txt");
+    fp=fopen(filename, "rb");
+    if(fp) {
+      char *mask_snapshot = (char *) malloc((len+1) * sizeof(char));
+      unsigned i;
+      bx_bool flag = 1;
+      fread(mask_snapshot, 1, len, fp);
+      fclose(fp);
+      for(i=0;i<len;i++) {
+       if((text_snapshot[i] != compare_snapshot[i]) &&
+          (compare_snapshot[i] == mask_snapshot[i])) {
+         flag = 0;
+         break;
+       }
+      }
+      if(flag) {
+       if(!memcmp(text_snapshot,compare_snapshot,len)) {
+         BX_PASS(("Test Passed."));
+       } else {
+         BX_PASS(("Test Passed with Mask."));
+       }
+      }
+    } else {
+      if(!memcmp(text_snapshot,compare_snapshot,len)) {
+       BX_PASS(("Test Passed."));
+      }
+    }
+    free(compare_snapshot);
+    free(text_snapshot);
+  }
+}
+
+// create a text snapshot and dump it to a file
+  void
+bx_gui_c::snapshot_handler(void)
+{
+  char *text_snapshot;
+  Bit32u len;
+  if (make_text_snapshot (&text_snapshot, &len) < 0) {
+    BX_ERROR(( "snapshot button failed, mode not implemented"));
+    return;
+  }
+  //FIXME
+  char filename[BX_PATHNAME_LEN];
+#ifdef WIN32
+  if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+              "rfb")) {
+#else
+  if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+              "wx")) {
+#endif
+    int ret = SIM->ask_filename (filename, sizeof(filename),
+                                 "Save snapshot as...", "snapshot.txt",
+                                 bx_param_string_c::SAVE_FILE_DIALOG);
+    if (ret < 0) { // cancelled
+      free(text_snapshot);
+      return;
+    }
+  } else {
+    strcpy (filename, "snapshot.txt");
+  }
+  FILE *fp = fopen(filename, "wb");
+  fwrite(text_snapshot, 1, len, fp);
+  fclose(fp);
+  free(text_snapshot);
+}
+
+// Read ASCII chars from the system clipboard and paste them into bochs.
+// Note that paste cannot work with the key mapping tables loaded.
+  void
+bx_gui_c::paste_handler(void)
+{
+  Bit32s nbytes;
+  Bit8u *bytes;
+  if (!bx_keymap.isKeymapLoaded ()) {
+    BX_ERROR (("keyboard_mapping disabled, so paste cannot work"));
+    return;
+  }
+  if (!BX_GUI_THIS get_clipboard_text(&bytes, &nbytes)) {
+    BX_ERROR (("paste not implemented on this platform"));
+    return;
+  }
+  BX_INFO (("pasting %d bytes", nbytes));
+  DEV_kbd_paste_bytes (bytes, nbytes);
+}
+
+
+  void
+bx_gui_c::config_handler(void)
+{
+  if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+              "rfb")) {
+    SIM->configuration_interface (NULL, CI_RUNTIME_CONFIG);
+  }
+}
+
+  void
+bx_gui_c::toggle_mouse_enable(void)
+{
+  int old = bx_options.Omouse_enabled->get ();
+  BX_DEBUG (("toggle mouse_enabled, now %d", !old));
+  bx_options.Omouse_enabled->set (!old);
+}
+
+  void
+bx_gui_c::userbutton_handler(void)
+{
+  unsigned shortcut[4];
+  unsigned p;
+  char *user_shortcut;
+  int i, len, ret = 1;
+
+  len = 0;
+#ifdef WIN32
+  if (strcmp(bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()),
+              "rfb")) {
+#else
+  if (!strcmp(bx_options.Osel_config->get_choice(bx_options.Osel_config->get()),
+              "wx")) {
+#endif
+    ret = SIM->ask_param (BXP_USER_SHORTCUT);
+  }
+  user_shortcut = bx_options.Ouser_shortcut->getptr();
+  if ((ret > 0) && user_shortcut[0] && (strcmp(user_shortcut, "none"))) {
+    len = 0;
+    p = 0;
+    while ((p < strlen(user_shortcut)) && (len < 3)) {
+      if (!strncmp(user_shortcut+p, "alt", 3)) {
+        shortcut[len++] = BX_KEY_ALT_L;
+        p += 3;
+      } else if (!strncmp(user_shortcut+p, "ctrl", 4)) {
+        shortcut[len++] = BX_KEY_CTRL_L;
+        p += 4;
+      } else if (!strncmp(user_shortcut+p, "del", 3)) {
+        shortcut[len++] = BX_KEY_DELETE;
+        p += 3;
+      } else if (!strncmp(user_shortcut+p, "esc", 3)) {
+        shortcut[len++] = BX_KEY_ESC;
+        p += 3;
+      } else if (!strncmp(user_shortcut+p, "f1", 2)) {
+        shortcut[len++] = BX_KEY_F1;
+        p += 2;
+      } else if (!strncmp(user_shortcut+p, "f4", 2)) {
+        shortcut[len++] = BX_KEY_F4;
+        p += 2;
+      } else if (!strncmp(user_shortcut+p, "tab", 3)) {
+        shortcut[len++] = BX_KEY_TAB;
+        p += 3;
+      } else if (!strncmp(user_shortcut+p, "win", 3)) {
+        shortcut[len++] = BX_KEY_WIN_L;
+        p += 3;
+      } else if (!strncmp(user_shortcut+p, "bksp", 4)) {
+        shortcut[len++] = BX_KEY_BACKSPACE;
+        p += 4;
+      } else {
+        BX_ERROR(("Unknown shortcut %s ignored", user_shortcut));
+        return;
+      }
+    }
+    i = 0;
+    while (i < len) {
+      DEV_kbd_gen_scancode(shortcut[i++]);
+    }
+    i--;
+    while (i >= 0) {
+      DEV_kbd_gen_scancode(shortcut[i--] | BX_KEY_RELEASED);
+    }
+  }
+}
+
+  void
+bx_gui_c::mouse_enabled_changed (bx_bool val)
+{
+  // This is only called when SIM->get_init_done is 1.  Note that VAL
+  // is the new value of mouse_enabled, which may not match the old
+  // value which is still in bx_options.Omouse_enabled->get ().
+  BX_DEBUG (("replacing the mouse bitmaps"));
+  if (val)
+    BX_GUI_THIS replace_bitmap(BX_GUI_THIS mouse_hbar_id, BX_GUI_THIS mouse_bmap_id);
+  else
+    BX_GUI_THIS replace_bitmap(BX_GUI_THIS mouse_hbar_id, BX_GUI_THIS nomouse_bmap_id);
+  // give the GUI a chance to respond to the event.  Most guis will hide
+  // the native mouse cursor and do something to trap the mouse inside the
+  // bochs VGA display window.
+  BX_GUI_THIS mouse_enabled_changed_specific (val);
+}
+
+void
+bx_gui_c::init_signal_handlers ()
+{
+#if BX_GUI_SIGHANDLER
+  if (bx_gui_sighandler) 
+  {
+    Bit32u mask = bx_gui->get_sighandler_mask ();
+    for (Bit32u sig=0; sig<32; sig++)
+    {
+      if (mask & (1<<sig))
+        signal (sig, bx_signal_handler);
+    }
+  }
+#endif
+}
+
+  void
+bx_gui_c::set_text_charmap(Bit8u *fbuffer)
+{
+  memcpy(& BX_GUI_THIS vga_charmap, fbuffer, 0x2000);
+  for (unsigned i=0; i<256; i++) BX_GUI_THIS char_changed[i] = 1;
+  BX_GUI_THIS charmap_updated = 1;
+}
+
+  void
+bx_gui_c::set_text_charbyte(Bit16u address, Bit8u data)
+{
+  BX_GUI_THIS vga_charmap[address] = data;
+  BX_GUI_THIS char_changed[address >> 5] = 1;
+  BX_GUI_THIS charmap_updated = 1;
+}
diff --git a/tools/ioemu/gui/gui.h b/tools/ioemu/gui/gui.h
new file mode 100644 (file)
index 0000000..14a44ca
--- /dev/null
@@ -0,0 +1,352 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gui.h,v 1.40 2003/06/28 08:04:31 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+typedef struct {
+  Bit8u cs_start;
+  Bit8u cs_end;
+  Bit16u line_offset;
+  Bit16u line_compare;
+  Bit8u h_panning;
+  Bit8u v_panning;
+  bx_bool line_graphics;
+} bx_vga_tminfo_t;
+
+
+BOCHSAPI extern class bx_gui_c *bx_gui;
+
+
+// The bx_gui_c class provides data and behavior that is common to
+// all guis.  Each gui implementation will override the abstract methods.
+class BOCHSAPI bx_gui_c : public logfunctions {
+public:
+  bx_gui_c (void);
+  virtual ~bx_gui_c ();
+  // Define the following functions in the module for your particular GUI
+  // (x.cc, beos.cc, ...)
+  virtual void specific_init(int argc, char **argv,
+                 unsigned x_tilesize, unsigned y_tilesize, unsigned header_bar_y) = 0;
+  virtual void text_update(Bit8u *old_text, Bit8u *new_text,
+                          unsigned long cursor_x, unsigned long cursor_y,
+                          bx_vga_tminfo_t tm_info, unsigned rows) = 0;
+  virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y) = 0;
+  virtual void handle_events(void) = 0;
+  virtual void flush(void) = 0;
+  virtual void clear_screen(void) = 0;
+  virtual bx_bool palette_change(unsigned index, unsigned red, unsigned green, unsigned blue) = 0;
+  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0, unsigned fwidth=0, unsigned bpp=8) = 0;
+  virtual unsigned create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim) = 0;
+  virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void)) = 0;
+  virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id) = 0;
+  virtual void show_headerbar(void) = 0;
+  virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)  = 0;
+  virtual int set_clipboard_text(char *snapshot, Bit32u len) = 0;
+  virtual void mouse_enabled_changed_specific (bx_bool val) = 0;
+  virtual void exit(void) = 0;
+  // set_display_mode() changes the mode between the configuration interface
+  // and the simulation.  This is primarily intended for display libraries
+  // which have a full-screen mode such as SDL, term, and svgalib.  The display
+  // mode is set to DISP_MODE_CONFIG before displaying any configuration menus,
+  // for panics that requires user input, when entering the debugger, etc.  It
+  // is set to DISP_MODE_SIM when the Bochs simulation resumes.  The
+  // enum is defined in gui/siminterface.h.
+  virtual void set_display_mode (disp_mode_t newmode) { /* default=no action*/ }
+  // These are only needed for the term gui. For all other guis they will
+  // have no effect.
+  // returns 32-bit bitmask in which 1 means the GUI should handle that signal
+  virtual Bit32u get_sighandler_mask () {return 0;}
+  // called when registered signal arrives
+  virtual void sighandler (int sig) {}
+#if BX_USE_IDLE_HACK
+  // this is called from the CPU model when the HLT instruction is executed.
+  virtual void sim_is_idle(void) {}
+#endif
+
+  // The following function(s) are defined already, and your
+  // GUI code calls them
+  static void key_event(Bit32u key);
+  static void set_text_charmap(Bit8u *fbuffer);
+  static void set_text_charbyte(Bit16u address, Bit8u data);
+
+  void init(int argc, char **argv,
+                 unsigned x_tilesize, unsigned y_tilesize);
+  void update_drive_status_buttons (void);
+  static void     mouse_enabled_changed (bx_bool val);
+  static void init_signal_handlers ();
+
+
+protected:
+  // And these are defined and used privately in gui.cc
+  static void floppyA_handler(void);
+  static void floppyB_handler(void);
+  static void cdromD_handler(void);
+  static void reset_handler(void);
+  static void power_handler(void);
+  static void copy_handler(void);
+  static void paste_handler(void);
+  static void snapshot_handler(void);
+  static void snapshot_checker(void *);
+  static void config_handler(void);
+  static void toggle_mouse_enable(void);
+  static void userbutton_handler(void);
+  static Bit32s make_text_snapshot (char **snapshot, Bit32u *length);
+
+  bx_bool floppyA_status;
+  bx_bool floppyB_status;
+  bx_bool cdromD_status;
+  unsigned floppyA_bmap_id, floppyA_eject_bmap_id, floppyA_hbar_id;
+  unsigned floppyB_bmap_id, floppyB_eject_bmap_id, floppyB_hbar_id;
+  unsigned cdromD_bmap_id, cdromD_eject_bmap_id, cdromD_hbar_id;
+  unsigned power_bmap_id,    power_hbar_id;
+  unsigned reset_bmap_id,    reset_hbar_id;
+  unsigned copy_bmap_id, copy_hbar_id;
+  unsigned paste_bmap_id, paste_hbar_id;
+  unsigned snapshot_bmap_id, snapshot_hbar_id;
+  unsigned config_bmap_id, config_hbar_id;
+  unsigned mouse_bmap_id, nomouse_bmap_id, mouse_hbar_id;
+  unsigned user_bmap_id, user_hbar_id;
+
+  unsigned char vga_charmap[0x2000];
+  bx_bool charmap_updated;
+  bx_bool char_changed[256];
+  disp_mode_t disp_mode;
+  };
+
+
+// Add this macro in the class declaration of each GUI, to define all the
+// required virtual methods.  Example:
+//   
+//    class bx_rfb_gui_c : public bx_gui_c {
+//    public:
+//      bx_rfb_gui_c (void) {}
+//      DECLARE_GUI_VIRTUAL_METHODS()
+//    };
+// Then, each method must be defined later in the file.
+#define DECLARE_GUI_VIRTUAL_METHODS()                                         \
+  virtual void specific_init(int argc, char **argv,                           \
+                 unsigned x_tilesize, unsigned y_tilesize,                    \
+                unsigned header_bar_y);                                      \
+  virtual void text_update(Bit8u *old_text, Bit8u *new_text,                  \
+                          unsigned long cursor_x, unsigned long cursor_y,     \
+                          bx_vga_tminfo_t tm_info, unsigned rows);            \
+  virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y); \
+  virtual void handle_events(void);                                           \
+  virtual void flush(void);                                                   \
+  virtual void clear_screen(void);                                            \
+  virtual bx_bool palette_change(unsigned index,                              \
+      unsigned red, unsigned green, unsigned blue);                           \
+  virtual void dimension_update(unsigned x, unsigned y, unsigned fheight=0,   \
+                                unsigned fwidth=0, unsigned bpp=8);           \
+  virtual unsigned create_bitmap(const unsigned char *bmap,                   \
+      unsigned xdim, unsigned ydim);                                          \
+  virtual unsigned headerbar_bitmap(unsigned bmap_id, unsigned alignment,     \
+      void (*f)(void));                                                       \
+  virtual void replace_bitmap(unsigned hbar_id, unsigned bmap_id);            \
+  virtual void show_headerbar(void);                                          \
+  virtual int get_clipboard_text(Bit8u **bytes, Bit32s *nbytes);              \
+  virtual int set_clipboard_text(char *snapshot, Bit32u len);                 \
+  virtual void mouse_enabled_changed_specific (bx_bool val);                  \
+  virtual void exit(void);                                                    \
+  /* end of DECLARE_GUI_VIRTUAL_METHODS */
+
+#define BX_MAX_PIXMAPS 16
+#define BX_MAX_HEADERBAR_ENTRIES 11
+#define BX_HEADER_BAR_Y 32
+
+// align pixmaps towards left or right side of header bar
+#define BX_GRAVITY_LEFT 10
+#define BX_GRAVITY_RIGHT 11
+
+#define BX_KEY_PRESSED  0x00000000
+#define BX_KEY_RELEASED 0x80000000
+
+#define BX_KEY_UNHANDLED 0x10000000
+
+#define BX_KEY_CTRL_L   0
+#define BX_KEY_SHIFT_L  1
+
+#define BX_KEY_F1     2
+#define BX_KEY_F2     3
+#define BX_KEY_F3     4
+#define BX_KEY_F4     5
+#define BX_KEY_F5     6
+#define BX_KEY_F6     7
+#define BX_KEY_F7     8
+#define BX_KEY_F8     9
+#define BX_KEY_F9    10
+#define BX_KEY_F10   11
+#define BX_KEY_F11   12
+#define BX_KEY_F12   13
+
+#define BX_KEY_CTRL_R    14
+#define BX_KEY_SHIFT_R   15
+#define BX_KEY_CAPS_LOCK 16
+#define BX_KEY_NUM_LOCK  17
+#define BX_KEY_ALT_L     18
+#define BX_KEY_ALT_R     19
+
+#define BX_KEY_A     20
+#define BX_KEY_B     21
+#define BX_KEY_C     22
+#define BX_KEY_D     23
+#define BX_KEY_E     24
+#define BX_KEY_F     25
+#define BX_KEY_G     26
+#define BX_KEY_H     27
+#define BX_KEY_I     28
+#define BX_KEY_J     29
+#define BX_KEY_K     30
+#define BX_KEY_L     31
+#define BX_KEY_M     32
+#define BX_KEY_N     33
+#define BX_KEY_O     34
+#define BX_KEY_P     35
+#define BX_KEY_Q     36
+#define BX_KEY_R     37
+#define BX_KEY_S     38
+#define BX_KEY_T     39
+#define BX_KEY_U     40
+#define BX_KEY_V     41
+#define BX_KEY_W     42
+#define BX_KEY_X     43
+#define BX_KEY_Y     44
+#define BX_KEY_Z     45
+
+#define BX_KEY_0     46
+#define BX_KEY_1     47
+#define BX_KEY_2     48
+#define BX_KEY_3     49
+#define BX_KEY_4     50
+#define BX_KEY_5     51
+#define BX_KEY_6     52
+#define BX_KEY_7     53
+#define BX_KEY_8     54
+#define BX_KEY_9     55
+
+#define BX_KEY_ESC    56
+
+#define BX_KEY_SPACE         57
+#define BX_KEY_SINGLE_QUOTE  58
+#define BX_KEY_COMMA         59
+#define BX_KEY_PERIOD        60
+#define BX_KEY_SLASH         61
+
+#define BX_KEY_SEMICOLON     62
+#define BX_KEY_EQUALS        63
+
+#define BX_KEY_LEFT_BRACKET  64
+#define BX_KEY_BACKSLASH     65
+#define BX_KEY_RIGHT_BRACKET 66
+#define BX_KEY_MINUS         67
+#define BX_KEY_GRAVE         68
+
+#define BX_KEY_BACKSPACE     69
+#define BX_KEY_ENTER         70
+#define BX_KEY_TAB           71
+
+#define BX_KEY_LEFT_BACKSLASH 72
+#define BX_KEY_PRINT         73
+#define BX_KEY_SCRL_LOCK     74
+#define BX_KEY_PAUSE         75
+
+#define BX_KEY_INSERT        76
+#define BX_KEY_DELETE        77
+#define BX_KEY_HOME          78
+#define BX_KEY_END           79
+#define BX_KEY_PAGE_UP       80
+#define BX_KEY_PAGE_DOWN     81
+
+#define BX_KEY_KP_ADD        82
+#define BX_KEY_KP_SUBTRACT   83
+#define BX_KEY_KP_END        84
+#define BX_KEY_KP_DOWN       85
+#define BX_KEY_KP_PAGE_DOWN  86
+#define BX_KEY_KP_LEFT       87
+#define BX_KEY_KP_RIGHT      88
+#define BX_KEY_KP_HOME       89
+#define BX_KEY_KP_UP         90
+#define BX_KEY_KP_PAGE_UP    91
+#define BX_KEY_KP_INSERT     92
+#define BX_KEY_KP_DELETE     93
+#define BX_KEY_KP_5          94
+
+#define BX_KEY_UP            95
+#define BX_KEY_DOWN          96
+#define BX_KEY_LEFT          97
+#define BX_KEY_RIGHT         98
+
+#define BX_KEY_KP_ENTER      99
+#define BX_KEY_KP_MULTIPLY  100
+#define BX_KEY_KP_DIVIDE    101
+
+#define BX_KEY_WIN_L        102
+#define BX_KEY_WIN_R        103
+#define BX_KEY_MENU         104
+
+#define BX_KEY_ALT_SYSREQ   105
+#define BX_KEY_CTRL_BREAK   106
+
+#define BX_KEY_INT_BACK     107
+#define BX_KEY_INT_FORWARD  108
+#define BX_KEY_INT_STOP     109
+#define BX_KEY_INT_MAIL     110
+#define BX_KEY_INT_SEARCH   111
+#define BX_KEY_INT_FAV      112
+#define BX_KEY_INT_HOME     113
+
+#define BX_KEY_POWER_MYCOMP 114
+#define BX_KEY_POWER_CALC   115
+#define BX_KEY_POWER_SLEEP  116
+#define BX_KEY_POWER_POWER  117
+#define BX_KEY_POWER_WAKE   118
+
+#define BX_KEY_NBKEYS       119
+// If you add BX_KEYs Please update 
+// - BX_KEY_NBKEYS
+// - the scancodes table in the file iodev/scancodes.cc
+// - the bx_key_symbol table in the file gui/keymap.cc
+
+
+/////////////// GUI plugin support
+
+// Define macro to supply gui plugin code.  This macro is called once in GUI to
+// supply the plugin initialization methods.  Since it is nearly identical for
+// each gui module, the macro is easier to maintain than pasting the same code
+// in each one.
+//
+// Each gui should declare a class pointer called "theGui" which is derived
+// from bx_gui_c, before calling this macro.  For example, the SDL port
+// says:
+//   static bx_sdl_gui_c *theGui;
+
+#define IMPLEMENT_GUI_PLUGIN_CODE(gui_name)                           \
+  int lib##gui_name##_LTX_plugin_init(plugin_t *plugin,               \
+          plugintype_t type, int argc, char *argv[]) {                \
+    genlog->info("installing %s module as the Bochs GUI", #gui_name); \
+    theGui = new bx_##gui_name##_gui_c ();                            \
+    bx_gui = theGui;                                                  \
+    return(0); /* Success */                                          \
+  }                                                                   \
+  void lib##gui_name##_LTX_plugin_fini(void) { }
diff --git a/tools/ioemu/gui/icon_bochs.h b/tools/ioemu/gui/icon_bochs.h
new file mode 100644 (file)
index 0000000..36669fe
--- /dev/null
@@ -0,0 +1,40 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: icon_bochs.h,v 1.3 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#define bochs_icon_width 32
+#define bochs_icon_height 32
+static unsigned char bochs_icon_bits[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+  0xe0, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f,
+  0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f,
+  0xfc, 0xc3, 0xc3, 0x3f, 0xf8, 0xc1, 0x83, 0x1f, 0xf0, 0xc0, 0x03, 0x0f,
+  0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+  0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
+  0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0xf0, 0xc0, 0x03, 0x0f,
+  0xf8, 0xc1, 0x83, 0x1f, 0xfc, 0xc3, 0xc3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f,
+  0xfc, 0xc7, 0xe3, 0x3f, 0xfc, 0xc7, 0xe3, 0x3f, 0xf8, 0xff, 0xff, 0x1f,
+  0xf8, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
diff --git a/tools/ioemu/gui/icon_bochs.xpm b/tools/ioemu/gui/icon_bochs.xpm
new file mode 100644 (file)
index 0000000..f895743
--- /dev/null
@@ -0,0 +1,45 @@
+/* XPM */
+static char *icon_bochs_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 7 1",
+"  c black",
+". c #800000",
+"X c #808000",
+"o c yellow",
+"O c #808080",
+"+ c #c0c0c0",
+"@ c None",
+/* pixels */
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@.    +@@@+  +@@@@@@@@@",
+"@@@@@@@@    Oo  @+     .@@@@@@@@",
+"@@@@@@    ooooo    ooo.  @@@@@@@",
+"@@@@   oooooo.    oooooX   @@@@@",
+"@+  XoooooO   XX   ooooooo  O@@@",
+"+  oooooO   XXXX X  ooooooo   @@",
+"@   ooo   XXXXXX XX   ooooooX   ",
+"@@.     XXXXXXXX XXX   Xooooo.  ",
+"@@@@  OXXXXXXXXX XXXXXO   oO  .@",
+"@@@@    .XXXXXXX XXXXXXX.    @@@",
+"@+   oo   XXXX    XXXXXXXX   @@@",
+"@   ooooo          XXXXXX      O",
+"@@O  oooooo  OXXXX.  XX  Oooo   ",
+"@@@@  .ooooo.  XXXXX    oooo  O@",
+"@@@@    Oooooo   XX.  .ooo   @@@",
+"@@@@ XX   oooooo    .oooo.  @@@@",
+"@@@@ ooXX   .        ooO  o @@@@",
+"@@@@ oooXX.   .Xo XX    XXo @@@@",
+"@@@@ ooooXXXXXXXo XXXX.XXoo @@@@",
+"@@@+ oooooooooooo XooXXXooo @@@@",
+"@@@. oooooooooooo Xooooooo  @@@@",
+"@@@+   oooooooooo XoooooX .@@@@@",
+"@@@@@O  XoooooooX ooooo  +@@@@@@",
+"@@@@@@@   ooooooX oooX  @@@@@@@@",
+"@@@@@@@@@   ooooX oo   @@@@@@@@@",
+"@@@@@@@@@@.  Ooo.    O@@@@@@@@@@",
+"@@@@@@@@@@@@        @@@@@@@@@@@@",
+"@@@@@@@@@@@@@@O   O@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@+@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
+"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+};
diff --git a/tools/ioemu/gui/keymap.cc b/tools/ioemu/gui/keymap.cc
new file mode 100644 (file)
index 0000000..8013693
--- /dev/null
@@ -0,0 +1,330 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keymap.cc,v 1.16 2003/10/11 10:43:24 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002 MandrakeSoft S.A.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Todo
+//  . Currently supported by sdl, wxGTK and x11. Check if other guis need mapping.
+//  . Tables look-up should be optimised.
+//
+
+#include "bochs.h"
+
+// Table of bochs "BX_KEY_*" symbols
+// the table must be in BX_KEY_* order
+char *bx_key_symbol[BX_KEY_NBKEYS] = {
+  "BX_KEY_CTRL_L",         "BX_KEY_SHIFT_L",        "BX_KEY_F1",
+  "BX_KEY_F2",             "BX_KEY_F3",             "BX_KEY_F4",
+  "BX_KEY_F5",             "BX_KEY_F6",             "BX_KEY_F7",
+  "BX_KEY_F8",             "BX_KEY_F9",             "BX_KEY_F10",
+  "BX_KEY_F11",            "BX_KEY_F12",            "BX_KEY_CTRL_R",
+  "BX_KEY_SHIFT_R",        "BX_KEY_CAPS_LOCK",      "BX_KEY_NUM_LOCK",
+  "BX_KEY_ALT_L",          "BX_KEY_ALT_R",          "BX_KEY_A",
+  "BX_KEY_B",              "BX_KEY_C",              "BX_KEY_D",
+  "BX_KEY_E",              "BX_KEY_F",              "BX_KEY_G",
+  "BX_KEY_H",              "BX_KEY_I",              "BX_KEY_J",
+  "BX_KEY_K",              "BX_KEY_L",              "BX_KEY_M",
+  "BX_KEY_N",              "BX_KEY_O",              "BX_KEY_P",
+  "BX_KEY_Q",              "BX_KEY_R",              "BX_KEY_S",
+  "BX_KEY_T",              "BX_KEY_U",              "BX_KEY_V",
+  "BX_KEY_W",              "BX_KEY_X",              "BX_KEY_Y",
+  "BX_KEY_Z",              "BX_KEY_0",              "BX_KEY_1",
+  "BX_KEY_2",              "BX_KEY_3",              "BX_KEY_4",
+  "BX_KEY_5",              "BX_KEY_6",              "BX_KEY_7",
+  "BX_KEY_8",              "BX_KEY_9",              "BX_KEY_ESC",
+  "BX_KEY_SPACE",          "BX_KEY_SINGLE_QUOTE",   "BX_KEY_COMMA",
+  "BX_KEY_PERIOD",         "BX_KEY_SLASH",          "BX_KEY_SEMICOLON",
+  "BX_KEY_EQUALS",         "BX_KEY_LEFT_BRACKET",   "BX_KEY_BACKSLASH",
+  "BX_KEY_RIGHT_BRACKET",  "BX_KEY_MINUS",          "BX_KEY_GRAVE",
+  "BX_KEY_BACKSPACE",      "BX_KEY_ENTER",          "BX_KEY_TAB",
+  "BX_KEY_LEFT_BACKSLASH", "BX_KEY_PRINT",          "BX_KEY_SCRL_LOCK",
+  "BX_KEY_PAUSE",          "BX_KEY_INSERT",         "BX_KEY_DELETE",
+  "BX_KEY_HOME",           "BX_KEY_END",            "BX_KEY_PAGE_UP",
+  "BX_KEY_PAGE_DOWN",      "BX_KEY_KP_ADD",         "BX_KEY_KP_SUBTRACT",
+  "BX_KEY_KP_END",         "BX_KEY_KP_DOWN",        "BX_KEY_KP_PAGE_DOWN",
+  "BX_KEY_KP_LEFT",        "BX_KEY_KP_RIGHT",       "BX_KEY_KP_HOME",
+  "BX_KEY_KP_UP",          "BX_KEY_KP_PAGE_UP",     "BX_KEY_KP_INSERT",
+  "BX_KEY_KP_DELETE",      "BX_KEY_KP_5",           "BX_KEY_UP",
+  "BX_KEY_DOWN",           "BX_KEY_LEFT",           "BX_KEY_RIGHT",
+  "BX_KEY_KP_ENTER",       "BX_KEY_KP_MULTIPLY",    "BX_KEY_KP_DIVIDE",
+  "BX_KEY_WIN_L",          "BX_KEY_WIN_R",          "BX_KEY_MENU",           
+  "BX_KEY_ALT_SYSREQ",     "BX_KEY_CTRL_BREAK",     "BX_KEY_INT_BACK",       
+  "BX_KEY_INT_FORWARD",    "BX_KEY_INT_STOP",       "BX_KEY_INT_MAIL",       
+  "BX_KEY_INT_SEARCH",     "BX_KEY_INT_FAV",        "BX_KEY_INT_HOME",       
+  "BX_KEY_POWER_MYCOMP",   "BX_KEY_POWER_CALC",     "BX_KEY_POWER_SLEEP",    
+  "BX_KEY_POWER_POWER",    "BX_KEY_POWER_WAKE",
+  };
+
+bx_keymap_c bx_keymap;
+
+#define LOG_THIS bx_keymap.
+
+bx_keymap_c::bx_keymap_c(void)
+{
+    put("KMAP");
+
+    keymapCount = 0;
+    keymapTable = (BXKeyEntry *)NULL;
+
+}
+
+bx_keymap_c::~bx_keymap_c(void)
+{
+    if(keymapTable != NULL) {
+      free(keymapTable);
+      keymapTable = (BXKeyEntry *)NULL;
+      }
+    keymapCount = 0;
+}
+
+    void
+bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*))
+{
+  if(bx_options.keyboard.OuseMapping->get()) {
+    loadKeymap(stringToSymbol,bx_options.keyboard.Okeymap->getptr());
+    }
+}
+
+
+bx_bool 
+bx_keymap_c::isKeymapLoaded ()
+{
+  return (keymapCount > 0);
+}
+
+
+///////////////////
+// I'll add these to the keymap object in a minute.
+static unsigned char *lineptr = NULL;
+static int lineCount;
+
+static void
+init_parse ()
+{
+  lineCount = 0;
+}
+
+static void
+init_parse_line (char *line_to_parse)
+{
+  // chop off newline
+  lineptr = (unsigned char *)line_to_parse;
+  char *nl;
+  if( (nl = strchr(line_to_parse,'\n')) != NULL) {
+    *nl = 0;
+  }
+}
+
+static Bit32s
+get_next_word (char *output)
+{
+  char *copyp = output;
+  // find first nonspace
+  while (*lineptr && isspace (*lineptr))
+    lineptr++;
+  if (!*lineptr) 
+    return -1;  // nothing but spaces until end of line
+  if (*lineptr == '#')
+    return -1;  // nothing but a comment
+  // copy nonspaces into the output
+  while (*lineptr && !isspace (*lineptr))
+    *copyp++ = *lineptr++;
+  *copyp=0;  // null terminate the copy
+  // there must be at least one nonspace, since that's why we stopped the
+  // first loop!
+  BX_ASSERT (copyp != output);
+  return 0;
+}
+
+static Bit32s
+get_next_keymap_line (FILE *fp, char *bxsym, char *modsym, Bit32s *ascii, char *hostsym)
+{
+  char line[256];
+  char buf[256];
+  line[0] = 0;
+  while (1) {
+    lineCount++;
+    if (!fgets(line, sizeof(line)-1, fp)) return -1;  // EOF
+    init_parse_line (line);
+    if (get_next_word (bxsym) >= 0) {
+      modsym[0] = 0;
+      char *p;
+      if ((p = strchr (bxsym, '+')) != NULL) {
+       *p = 0;  // truncate bxsym.
+       p++;  // move one char beyond the +
+       strcpy (modsym, p);  // copy the rest to modsym
+      }
+      if (get_next_word (buf) < 0) {
+       BX_PANIC (("keymap line %d: expected 3 columns", lineCount));
+       return -1;
+      }
+      if (buf[0] == '\'' && buf[2] == '\'' && buf[3]==0) {
+       *ascii = (Bit8u) buf[1];
+      } else if (!strcmp(buf, "space")) {
+       *ascii = ' ';
+      } else if (!strcmp(buf, "return")) {
+       *ascii = '\n';
+      } else if (!strcmp(buf, "tab")) {
+       *ascii = '\t';
+      } else if (!strcmp(buf, "backslash")) {
+       *ascii = '\\';
+      } else if (!strcmp(buf, "apostrophe")) {
+       *ascii = '\'';
+      } else if (!strcmp(buf, "none")) {
+       *ascii = -1;
+      } else {
+       BX_PANIC (("keymap line %d: ascii equivalent is \"%s\" but it must be char constant like 'x', or one of space,tab,return,none", lineCount, buf));
+      }
+      if (get_next_word (hostsym) < 0) {
+        BX_PANIC (("keymap line %d: expected 3 columns", lineCount));
+       return -1;
+      }
+      return 0;
+    }
+    // no words on this line, keep reading.
+  }
+}
+
+    void
+bx_keymap_c::loadKeymap(Bit32u stringToSymbol(const char*), const char* filename)
+{
+    FILE   *keymapFile;
+    char baseSym[256], modSym[256], hostSym[256]; 
+    Bit32s ascii;
+    Bit32u baseKey, modKey, hostKey;
+    struct stat status;
+
+    if (stat(filename, &status)) {
+      BX_PANIC(("Can not stat keymap file '%s'.",filename));
+      }
+
+    if (!(S_ISREG(status.st_mode))) {
+      BX_PANIC(("Keymap file '%s' is not a file",filename));
+      }
+
+    if((keymapFile = fopen(filename,"r"))==NULL) {
+      BX_PANIC(("Can not open keymap file '%s'.",filename));
+      }
+    
+    BX_INFO(("Loading keymap from '%s'",filename));
+    init_parse ();
+
+    // Read keymap file one line at a time
+    while(1) {
+      if (get_next_keymap_line (keymapFile, 
+            baseSym, modSym, &ascii, hostSym) < 0) { break; }
+
+
+      // convert X_KEY_* symbols to values
+      baseKey = convertStringToBXKey(baseSym);
+      modKey = convertStringToBXKey(modSym);
+      hostKey = 0;
+      if (stringToSymbol != NULL)
+        hostKey = stringToSymbol(hostSym);
+
+      BX_DEBUG (("baseKey='%s' (%d), modSym='%s' (%d), ascii=%d, guisym='%s' (%d)", baseSym, baseKey, modSym, modKey, ascii, hostSym, hostKey));
+       
+      // Check if data is valid
+      if( baseKey==BX_KEYMAP_UNKNOWN ) {
+        BX_PANIC (("line %d: unknown BX_KEY constant '%s'",lineCount,baseSym));
+        continue;
+        }
+
+      if( hostKey==BX_KEYMAP_UNKNOWN ) {
+        BX_PANIC (("line %d: unknown host key name '%s'",lineCount,hostSym));
+        continue;
+        }
+
+      keymapTable=(BXKeyEntry*)realloc(keymapTable,(keymapCount+1) * sizeof(BXKeyEntry));
+      
+      if(keymapTable==NULL) 
+        BX_PANIC(("Can not allocate memory for keymap table."));
+
+      keymapTable[keymapCount].baseKey=baseKey;
+      keymapTable[keymapCount].modKey=modKey;
+      keymapTable[keymapCount].ascii=ascii;
+      keymapTable[keymapCount].hostKey=hostKey;
+      
+      keymapCount++;
+      }
+
+    BX_INFO(("Loaded %d symbols",keymapCount));
+
+    fclose(keymapFile);
+}
+
+    Bit32u
+bx_keymap_c::convertStringToBXKey(const char* string)
+{
+    Bit16u i;
+
+    // We look through the bx_key_symbol table to find the searched string
+    for (i=0; i<BX_KEY_NBKEYS; i++) {
+      if (strcmp(string,bx_key_symbol[i])==0) {
+        return i;
+        }
+      }
+  
+    // Key is not known
+    return BX_KEYMAP_UNKNOWN;
+}
+
+    BXKeyEntry *
+bx_keymap_c::findHostKey(Bit32u key)
+{
+    Bit16u i;
+
+    // We look through the keymap table to find the searched key
+    for (i=0; i<keymapCount; i++) {
+      if (keymapTable[i].hostKey == key) {
+       BX_DEBUG (("key 0x%02x matches hostKey for entry #%d", key, i));
+        return &keymapTable[i];
+        }
+      }
+    BX_DEBUG (("key %02x matches no entries", key));
+
+    // Return default
+    return NULL;
+}
+
+    BXKeyEntry *
+bx_keymap_c::findAsciiChar(Bit8u ch)
+{
+    Bit16u i;
+    BX_DEBUG (("findAsciiChar (0x%02x)", ch));
+
+    // We look through the keymap table to find the searched key
+    for (i=0; i<keymapCount; i++) {
+      if (keymapTable[i].ascii == ch) {
+       BX_DEBUG (("key %02x matches ascii for entry #%d", ch, i));
+        return &keymapTable[i];
+        }
+      }
+    BX_DEBUG (("key 0x%02x matches no entries", ch));
+
+    // Return default
+    return NULL;
+}
+
+    char *
+bx_keymap_c::getBXKeyName(Bit32u key)
+{
+    return bx_key_symbol[key & 0x7fffffff];
+}
diff --git a/tools/ioemu/gui/keymap.h b/tools/ioemu/gui/keymap.h
new file mode 100644 (file)
index 0000000..945729b
--- /dev/null
@@ -0,0 +1,77 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keymap.h,v 1.9 2003/07/12 08:17:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Methods of bx_keymap_c :
+//
+// - loadKeymap(Bit32u convertStringToSymbol(const char*));
+//   loads the configuration specified keymap file if keymapping is enabled
+//   using convertStringToSymbol to convert strings to client constants
+//
+// - loadKeymap(Bit32u convertStringToSymbol(const char*), const char* filename);
+//   loads the specified keymap file 
+//   using convertStringToSymbol to convert strings to client constants
+//
+// - isKeymapLoaded () returns true if the keymap contains any valid key
+//   entries.
+//
+// - convertStringToBXKey
+//   convert a null-terminate string to a BX_KEY code
+//
+// - findHostKey(Bit32u key)
+// - findAsciiChar(Bit8u ch)
+//   Each of these methods returns a pointer to a BXKeyEntry structure
+//   corresponding to a key.  findHostKey() finds an entry whose hostKey
+//   value matches the target value, and findAsciiChar() finds an entry
+//   whose ASCII code matches the search value.
+
+// In case of unknown symbol
+#define BX_KEYMAP_UNKNOWN   0xFFFFFFFF
+
+// Structure of an element of the keymap table
+typedef struct BOCHSAPI { 
+  Bit32u baseKey;   // base key
+  Bit32u modKey;   // modifier key that must be held down
+  Bit32s ascii;    // ascii equivalent, if any
+  Bit32u hostKey;  // value that the host's OS or library recognizes
+  } BXKeyEntry;
+
+class BOCHSAPI bx_keymap_c : public logfunctions {
+public:
+  bx_keymap_c(void);
+  ~bx_keymap_c(void);
+
+  void   loadKeymap(Bit32u(*)(const char*));
+  void   loadKeymap(Bit32u(*)(const char*),const char *filename);
+  bx_bool isKeymapLoaded ();
+
+  BXKeyEntry *findHostKey(Bit32u hostkeynum);
+  BXKeyEntry *findAsciiChar(Bit8u ascii);
+  char *getBXKeyName(Bit32u key);
+
+private:
+  Bit32u convertStringToBXKey(const char *);
+  BXKeyEntry *keymapTable;
+  Bit16u   keymapCount;
+  };
+
+BOCHSAPI extern bx_keymap_c bx_keymap;
diff --git a/tools/ioemu/gui/keymaps/convertmap.pl b/tools/ioemu/gui/keymaps/convertmap.pl
new file mode 100644 (file)
index 0000000..18c47be
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+# little utility script that I used to convert key map files from
+# the pre-March 11 format to the post-March 11 format.  It doesn't
+# do anything smart with the ascii equivalents and modifiers, so ATM those must
+# be added by hand.
+
+while (<STDIN>)
+{
+  chop;
+  s/^ *//;
+  if (/^#/ || /^ *$/) { print "$_\n"; next;}
+  ($key, $equals, $xksym) = split (/ +/);
+  printf ("%-45s %-10s %s\n", $key, 'none', "XK_$xksym");
+}
diff --git a/tools/ioemu/gui/keymaps/sdl-pc-de.map b/tools/ioemu/gui/keymaps/sdl-pc-de.map
new file mode 100644 (file)
index 0000000..de4fd59
--- /dev/null
@@ -0,0 +1,222 @@
+# Bochs Keymap file
+# $Id: sdl-pc-de.map,v 1.2 2002/10/24 21:06:55 bdenney Exp $
+# Target: PC(x86) keyboard, DE keymap, SDL gui on X11
+# Author: Volker Ruppert
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Host_key_name
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent      Host_key_name
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Host_key_name is the name of the key combination according to the gui library
+# (X windows, SDL, etc).  Each GUI module must provide a function that converts
+# these host key names into numbers.  A pointer to the conversion function is
+# passed to loadKeymap(), and it is used when parsing the keymap file.  As the
+# keymap file is parsed, the conversion function is called for each host key
+# name, to convert it into a number.  Only the number is stored.  If the host
+# key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and
+# the keymap code will panic, like this: 
+#
+#    [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT' 
+#
+# If this happens, you must edit the keymap file, and either correct the host
+# key name or comment out that line.
+#
+
+BX_KEY_0                                      '0'        SDLK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       '='        SDLK_EQUALS
+BX_KEY_1                                      '1'        SDLK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        SDLK_EXCLAIM
+BX_KEY_2                                      '2'        SDLK_2
+BX_KEY_2+BX_KEY_ALT_R                         '²'        SDLK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '"'        SDLK_QUOTEDBL
+BX_KEY_3                                      '3'        SDLK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '§'        SDLK_3
+BX_KEY_4                                      '4'        SDLK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        SDLK_DOLLAR
+BX_KEY_4+BX_KEY_ALT_R                         '¼'        SDLK_4
+BX_KEY_5                                      '5'        SDLK_5
+BX_KEY_5+BX_KEY_ALT_R                         '½'        SDLK_5
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        SDLK_5
+BX_KEY_6                                      '6'        SDLK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '&'        SDLK_AMPERSAND
+BX_KEY_7                                      '7'        SDLK_7
+BX_KEY_7+BX_KEY_ALT_R                         '{'        SDLK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '/'        SDLK_SLASH
+BX_KEY_8                                      '8'        SDLK_8
+BX_KEY_8+BX_KEY_ALT_R                         '['        SDLK_LEFTBRACKET
+BX_KEY_8+BX_KEY_SHIFT_L                       '('        SDLK_LEFTPAREN
+BX_KEY_9                                      '9'        SDLK_9
+BX_KEY_9+BX_KEY_ALT_R                         ']'        SDLK_RIGHTBRACKET
+BX_KEY_9+BX_KEY_SHIFT_L                       ')'        SDLK_RIGHTPAREN
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        SDLK_a
+BX_KEY_A                                      'a'        SDLK_a
+BX_KEY_A+BX_KEY_ALT_R                         'æ'        SDLK_a
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        SDLK_b
+BX_KEY_B                                      'b'        SDLK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        SDLK_c
+BX_KEY_C                                      'c'        SDLK_c
+BX_KEY_C+BX_KEY_ALT_R                         '¢'        SDLK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        SDLK_d
+BX_KEY_D                                      'd'        SDLK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        SDLK_e
+BX_KEY_E+BX_KEY_ALT_R                         none       SDLK_EURO
+BX_KEY_E                                      'e'        SDLK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        SDLK_f
+BX_KEY_F                                      'f'        SDLK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        SDLK_g
+BX_KEY_G                                      'g'        SDLK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        SDLK_h
+BX_KEY_H                                      'h'        SDLK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        SDLK_i
+BX_KEY_I                                      'i'        SDLK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        SDLK_j
+BX_KEY_J                                      'j'        SDLK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        SDLK_k
+BX_KEY_K                                      'k'        SDLK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        SDLK_l
+BX_KEY_L                                      'l'        SDLK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        SDLK_m
+BX_KEY_M                                      'm'        SDLK_m
+BX_KEY_M+BX_KEY_ALT_R                         'µ'        SDLK_m
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        SDLK_n
+BX_KEY_N                                      'n'        SDLK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        SDLK_o
+BX_KEY_O                                      'o'        SDLK_o
+BX_KEY_O+BX_KEY_ALT_R                         'ø'        SDLK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        SDLK_p
+BX_KEY_P                                      'p'        SDLK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        SDLK_q
+BX_KEY_Q+BX_KEY_ALT_R                         '@'        SDLK_AT
+BX_KEY_Q                                      'q'        SDLK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        SDLK_r
+BX_KEY_R+BX_KEY_ALT_R                         '¶'        SDLK_r
+BX_KEY_R                                      'r'        SDLK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        SDLK_s
+BX_KEY_S                                      's'        SDLK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        SDLK_t
+BX_KEY_T                                      't'        SDLK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        SDLK_u
+BX_KEY_U                                      'u'        SDLK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        SDLK_v
+BX_KEY_V                                      'v'        SDLK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        SDLK_w
+BX_KEY_W                                      'w'        SDLK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        SDLK_x
+BX_KEY_X+BX_KEY_ALT_R                         '»'        SDLK_x
+BX_KEY_X                                      'x'        SDLK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Z'        SDLK_z
+BX_KEY_Y                                      'z'        SDLK_z
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Y'        SDLK_y
+BX_KEY_Z+BX_KEY_ALT_R                         '«'        SDLK_y
+BX_KEY_Z                                      'y'        SDLK_y
+BX_KEY_F1                                     none       SDLK_F1
+BX_KEY_F2                                     none       SDLK_F2
+BX_KEY_F3                                     none       SDLK_F3
+BX_KEY_F4                                     none       SDLK_F4
+BX_KEY_F5                                     none       SDLK_F5
+BX_KEY_F6                                     none       SDLK_F6
+BX_KEY_F7                                     none       SDLK_F7
+BX_KEY_F8                                     none       SDLK_F8
+BX_KEY_F9                                     none       SDLK_F9
+BX_KEY_F10                                    none       SDLK_F10
+BX_KEY_F11                                    none       SDLK_F11
+BX_KEY_F12                                    none       SDLK_F12
+BX_KEY_ALT_L                                  none       SDLK_LALT
+BX_KEY_ALT_L                                  none       SDLK_LMETA
+BX_KEY_ALT_R                                  none       SDLK_RALT
+BX_KEY_ALT_R                                  none       SDLK_MODE
+BX_KEY_BACKSLASH                              apostrophe SDLK_QUOTE
+BX_KEY_BACKSLASH                              '#'        SDLK_HASH
+BX_KEY_BACKSPACE                              none       SDLK_BACKSPACE
+BX_KEY_CAPS_LOCK                              none       SDLK_CAPSLOCK
+BX_KEY_COMMA                                  ','        SDLK_COMMA
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   ';'        SDLK_SEMICOLON
+BX_KEY_CTRL_L                                 none       SDLK_LCTRL
+BX_KEY_CTRL_R                                 none       SDLK_RCTRL
+BX_KEY_DELETE                                 none       SDLK_DELETE
+BX_KEY_DOWN                                   none       SDLK_DOWN
+BX_KEY_END                                    none       SDLK_END
+BX_KEY_ENTER                                  return     SDLK_RETURN
+BX_KEY_EQUALS                                 none       SDLK_WORLD_20
+BX_KEY_EQUALS+BX_KEY_ALT_R                    '¸'        SDLK_WORLD_20
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '`'        SDLK_WORLD_20
+BX_KEY_ESC                                    none       SDLK_ESCAPE
+BX_KEY_GRAVE                                  '^'        SDLK_CARET
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '°'        SDLK_CARET
+BX_KEY_GRAVE+BX_KEY_ALT_R                     '¬'        SDLK_CARET
+BX_KEY_HOME                                   none       SDLK_HOME
+BX_KEY_INSERT                                 none       SDLK_INSERT
+BX_KEY_KP_5                                   none       SDLK_KP5
+BX_KEY_KP_ADD                                 none       SDLK_KP_PLUS
+BX_KEY_KP_DELETE                              none       SDLK_KP_PERIOD
+BX_KEY_KP_DIVIDE                              none       SDLK_KP_DIVIDE
+BX_KEY_KP_DOWN                                none       SDLK_KP2
+BX_KEY_KP_END                                 none       SDLK_KP1
+BX_KEY_KP_ENTER                               none       SDLK_KP_ENTER
+BX_KEY_KP_HOME                                none       SDLK_KP7
+BX_KEY_KP_INSERT                              none       SDLK_KP0
+BX_KEY_KP_LEFT                                none       SDLK_KP4
+BX_KEY_KP_MULTIPLY                            none       SDLK_KP_MULTIPLY
+BX_KEY_KP_PAGE_DOWN                           none       SDLK_KP3
+BX_KEY_KP_PAGE_UP                             none       SDLK_KP9
+BX_KEY_KP_RIGHT                               none       SDLK_KP6
+BX_KEY_KP_SUBTRACT                            none       SDLK_KP_MINUS
+BX_KEY_KP_UP                                  none       SDLK_KP8
+BX_KEY_LEFT                                   none       SDLK_LEFT
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R            '|'        SDLK_LESS
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        SDLK_GREATER
+BX_KEY_LEFT_BACKSLASH                         '<'        SDLK_LESS
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            'Ü'        SDLK_WORLD_92
+BX_KEY_LEFT_BRACKET                           'ü'        SDLK_WORLD_92
+BX_KEY_MENU                                   none       SDLK_MENU
+BX_KEY_MINUS+BX_KEY_ALT_L                     backslash  SDLK_BACKSLASH
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '?'        SDLK_QUESTION
+BX_KEY_MINUS                                  'ß'        SDLK_WORLD_63
+BX_KEY_NUM_LOCK                               none       SDLK_NUMLOCK
+BX_KEY_PAGE_DOWN                              none       SDLK_PAGEDOWN
+BX_KEY_PAGE_UP                                none       SDLK_PAGEUP
+BX_KEY_PAUSE                                  none       SDLK_BREAK
+BX_KEY_PAUSE                                  none       SDLK_PAUSE
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  ':'        SDLK_COLON
+BX_KEY_PERIOD                                 '.'        SDLK_PERIOD
+BX_KEY_PERIOD+BX_KEY_ALT_L                    '·'        SDLK_PERIOD
+BX_KEY_PRINT                                  none       SDLK_PRINT
+BX_KEY_PRINT                                  none       SDLK_SYSREQ
+BX_KEY_RIGHT                                  none       SDLK_RIGHT
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             '~'        SDLK_PLUS
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '*'        SDLK_PLUS
+BX_KEY_RIGHT_BRACKET                          '+'        SDLK_PLUS
+BX_KEY_SCRL_LOCK                              none       SDLK_SCROLLOCK
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'Ö'        SDLK_WORLD_86
+BX_KEY_SEMICOLON                              'ö'        SDLK_WORLD_86
+BX_KEY_SHIFT_L                                none       SDLK_LSHIFT
+BX_KEY_SHIFT_R                                none       SDLK_RSHIFT
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            'Ä'        SDLK_WORLD_68
+BX_KEY_SINGLE_QUOTE                           'ä'        SDLK_WORLD_68
+BX_KEY_SLASH                                  '-'        SDLK_MINUS
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '_'        SDLK_UNDERSCORE
+BX_KEY_SPACE                                  space      SDLK_SPACE
+BX_KEY_TAB                                    tab        SDLK_TAB
+BX_KEY_UP                                     none       SDLK_UP
+BX_KEY_WIN_L                                  none       SDLK_LSUPER
+BX_KEY_WIN_R                                  none       SDLK_RSUPER
diff --git a/tools/ioemu/gui/keymaps/sdl-pc-us.map b/tools/ioemu/gui/keymaps/sdl-pc-us.map
new file mode 100644 (file)
index 0000000..3440992
--- /dev/null
@@ -0,0 +1,211 @@
+# Bochs Keymap file
+# $Id: sdl-pc-us.map,v 1.2 2002/10/24 21:06:55 bdenney Exp $
+# Target: PC(x86) keyboard, US keymap, SDL gui
+# Author: Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Host_key_name
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent      Host_key_name
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Host_key_name is the name of the key combination according to the gui library
+# (X windows, SDL, etc).  Each GUI module must provide a function that converts
+# these host key names into numbers.  A pointer to the conversion function is
+# passed to loadKeymap(), and it is used when parsing the keymap file.  As the
+# keymap file is parsed, the conversion function is called for each host key
+# name, to convert it into a number.  Only the number is stored.  If the host
+# key name is not found, the conversion function returns BX_KEYMAP_UNKNOWN, and
+# the keymap code will panic, like this: 
+#
+#    [KMAP ] line 51: unknown host key name 'SDLK_PAREN_RIGHT' 
+#
+# If this happens, you must edit the keymap file, and either correct the host
+# key name or comment out that line.
+#
+
+BX_KEY_0                                      '0'        SDLK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       ')'        SDLK_RIGHTPAREN
+BX_KEY_1                                      '1'        SDLK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        SDLK_EXCLAIM
+BX_KEY_2                                      '2'        SDLK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '@'        SDLK_AT
+BX_KEY_3                                      '3'        SDLK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '#'        SDLK_HASH
+BX_KEY_4                                      '4'        SDLK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        SDLK_DOLLAR
+BX_KEY_5                                      '5'        SDLK_5
+#BX_KEY_5+BX_KEY_SHIFT_L                       '%'        SDLK_PERCENT
+BX_KEY_6                                      '6'        SDLK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '^'        SDLK_CARET
+BX_KEY_7                                      '7'        SDLK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '&'        SDLK_AMPERSAND
+BX_KEY_8                                      '8'        SDLK_8
+BX_KEY_8+BX_KEY_SHIFT_L                       '*'        SDLK_ASTERISK
+BX_KEY_9                                      '9'        SDLK_9
+BX_KEY_9+BX_KEY_SHIFT_L                       '('        SDLK_LEFTPAREN
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        SDLK_a
+BX_KEY_A                                      'a'        SDLK_a
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        SDLK_b
+BX_KEY_B                                      'b'        SDLK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        SDLK_c
+BX_KEY_C                                      'c'        SDLK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        SDLK_d
+BX_KEY_D                                      'd'        SDLK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        SDLK_e
+BX_KEY_E                                      'e'        SDLK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        SDLK_f
+BX_KEY_F                                      'f'        SDLK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        SDLK_g
+BX_KEY_G                                      'g'        SDLK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        SDLK_h
+BX_KEY_H                                      'h'        SDLK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        SDLK_i
+BX_KEY_I                                      'i'        SDLK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        SDLK_j
+BX_KEY_J                                      'j'        SDLK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        SDLK_k
+BX_KEY_K                                      'k'        SDLK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        SDLK_l
+BX_KEY_L                                      'l'        SDLK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        SDLK_m
+BX_KEY_M                                      'm'        SDLK_m
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        SDLK_n
+BX_KEY_N                                      'n'        SDLK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        SDLK_o
+BX_KEY_O                                      'o'        SDLK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        SDLK_p
+BX_KEY_P                                      'p'        SDLK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        SDLK_q
+BX_KEY_Q                                      'q'        SDLK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        SDLK_r
+BX_KEY_R                                      'r'        SDLK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        SDLK_s
+BX_KEY_S                                      's'        SDLK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        SDLK_t
+BX_KEY_T                                      't'        SDLK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        SDLK_u
+BX_KEY_U                                      'u'        SDLK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        SDLK_v
+BX_KEY_V                                      'v'        SDLK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        SDLK_w
+BX_KEY_W                                      'w'        SDLK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        SDLK_x
+BX_KEY_X                                      'x'        SDLK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        SDLK_y
+BX_KEY_Y                                      'y'        SDLK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        SDLK_z
+BX_KEY_Z                                      'z'        SDLK_z
+BX_KEY_F1                                     none       SDLK_F1
+BX_KEY_F2                                     none       SDLK_F2
+BX_KEY_F3                                     none       SDLK_F3
+BX_KEY_F4                                     none       SDLK_F4
+BX_KEY_F5                                     none       SDLK_F5
+BX_KEY_F6                                     none       SDLK_F6
+BX_KEY_F7                                     none       SDLK_F7
+BX_KEY_F8                                     none       SDLK_F8
+BX_KEY_F9                                     none       SDLK_F9
+BX_KEY_F10                                    none       SDLK_F10
+BX_KEY_F11                                    none       SDLK_F11
+BX_KEY_F12                                    none       SDLK_F12
+BX_KEY_ALT_L                                  none       SDLK_LALT
+BX_KEY_ALT_L                                  none       SDLK_LMETA
+BX_KEY_ALT_R                                  none       SDLK_MODE
+#BX_KEY_ALT_R                                  none       SDLK_Multi_key
+BX_KEY_BACKSLASH                              backslash  SDLK_BACKSLASH
+#BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '|'        SDLK_bar
+BX_KEY_BACKSPACE                              none       SDLK_BACKSPACE
+BX_KEY_CAPS_LOCK                              none       SDLK_CAPSLOCK
+BX_KEY_COMMA                                  ','        SDLK_COMMA
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   '<'        SDLK_LESS
+BX_KEY_CTRL_L                                 none       SDLK_LCTRL
+BX_KEY_CTRL_R                                 none       SDLK_RCTRL
+BX_KEY_DELETE                                 none       SDLK_DELETE
+BX_KEY_DOWN                                   none       SDLK_DOWN
+BX_KEY_END                                    none       SDLK_END
+BX_KEY_ENTER                                  return     SDLK_RETURN
+BX_KEY_EQUALS                                 '='        SDLK_EQUALS
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '+'        SDLK_PLUS
+BX_KEY_ESC                                    none       SDLK_ESCAPE
+#BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '~'        SDLK_asciitilde
+BX_KEY_GRAVE                                  '`'        SDLK_BACKQUOTE
+BX_KEY_HOME                                   none       SDLK_HOME
+BX_KEY_INSERT                                 none       SDLK_INSERT
+BX_KEY_KP_5                                   none       SDLK_KP5
+#BX_KEY_KP_5                                   none       SDLK_KP_BEGIN
+BX_KEY_KP_ADD                                 none       SDLK_KP_PLUS
+BX_KEY_KP_DELETE                              none       SDLK_KP_PERIOD
+#BX_KEY_KP_DELETE                              none       SDLK_KP_DELETE
+BX_KEY_KP_DIVIDE                              none       SDLK_KP_DIVIDE
+BX_KEY_KP_DOWN                                none       SDLK_KP2
+#BX_KEY_KP_DOWN                                none       SDLK_KP_DOWN
+BX_KEY_KP_END                                 none       SDLK_KP1
+#BX_KEY_KP_END                                 none       SDLK_KP_END
+BX_KEY_KP_ENTER                               none       SDLK_KP_ENTER
+BX_KEY_KP_HOME                                none       SDLK_KP7
+#BX_KEY_KP_HOME                                none       SDLK_KP_HOME
+BX_KEY_KP_INSERT                              none       SDLK_KP0
+#BX_KEY_KP_INSERT                              none       SDLK_KP_INSERT
+BX_KEY_KP_LEFT                                none       SDLK_KP4
+#BX_KEY_KP_LEFT                                none       SDLK_KP_LEFT
+BX_KEY_KP_MULTIPLY                            none       SDLK_KP_MULTIPLY
+BX_KEY_KP_PAGE_DOWN                           none       SDLK_KP3
+#BX_KEY_KP_PAGE_DOWN                           none       SDLK_KP_PAGE_DOWN
+BX_KEY_KP_PAGE_UP                             none       SDLK_KP9
+#BX_KEY_KP_PAGE_UP                             none       SDLK_KP_PAGE_UP
+BX_KEY_KP_RIGHT                               none       SDLK_KP6
+#BX_KEY_KP_RIGHT                               none       SDLK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       SDLK_KP_MINUS
+BX_KEY_KP_UP                                  none       SDLK_KP8
+#BX_KEY_KP_UP                                  none       SDLK_KP_Up
+BX_KEY_LEFT                                   none       SDLK_LEFT
+#BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            '{'        SDLK_BRACELEFT
+BX_KEY_LEFT_BRACKET                           '['        SDLK_LEFTBRACKET
+BX_KEY_MENU                                   none       SDLK_MENU
+BX_KEY_MINUS                                  '-'        SDLK_MINUS
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '_'        SDLK_UNDERSCORE
+BX_KEY_NUM_LOCK                               none       SDLK_NUMLOCK
+BX_KEY_PAGE_DOWN                              none       SDLK_PAGEDOWN
+BX_KEY_PAGE_UP                                none       SDLK_PAGEUP
+BX_KEY_PAUSE                                  none       SDLK_BREAK
+BX_KEY_PAUSE                                  none       SDLK_PAUSE
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  '>'        SDLK_GREATER
+BX_KEY_PERIOD                                 '.'        SDLK_PERIOD
+BX_KEY_PRINT                                  none       SDLK_PRINT
+BX_KEY_PRINT                                  none       SDLK_SYSREQ
+BX_KEY_RIGHT                                  none       SDLK_RIGHT
+#BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '}'        SDLK_BRACERIGHT
+BX_KEY_RIGHT_BRACKET                          ']'        SDLK_RIGHTBRACKET
+BX_KEY_SCRL_LOCK                              none       SDLK_SCROLLOCK
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               ':'        SDLK_COLON
+BX_KEY_SEMICOLON                              ';'        SDLK_SEMICOLON
+BX_KEY_SHIFT_L                                none       SDLK_LSHIFT
+BX_KEY_SHIFT_R                                none       SDLK_RSHIFT
+BX_KEY_SINGLE_QUOTE                           apostrophe SDLK_QUOTE
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '"'        SDLK_QUOTEDBL
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '?'        SDLK_QUESTION
+BX_KEY_SLASH                                  '/'        SDLK_SLASH
+BX_KEY_SPACE                                  space      SDLK_SPACE
+#BX_KEY_TAB                                    none       SDLK_ISO_LEFT_TAB
+BX_KEY_TAB                                    tab        SDLK_TAB
+BX_KEY_UP                                     none       SDLK_UP
+BX_KEY_WIN_L                                  none       SDLK_LSUPER
+BX_KEY_WIN_R                                  none       SDLK_LSUPER
diff --git a/tools/ioemu/gui/keymaps/x11-pc-be.map b/tools/ioemu/gui/keymaps/x11-pc-be.map
new file mode 100644 (file)
index 0000000..0a607e0
--- /dev/null
@@ -0,0 +1,220 @@
+# Bochs Keymap file
+# $Id: x11-pc-be.map,v 1.2 2003/07/29 13:31:11 bdenney Exp $
+# Target: PC(x86) keyboard, BE keymap
+# Author: Wouter Verhelst,
+# based on FR keymap by Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0+BX_KEY_SHIFT_L                       '0'        XK_0
+BX_KEY_0                                      'à'        XK_agrave
+BX_KEY_0+BX_KEY_ALT_R                         '}'        XK_braceright
+BX_KEY_1+BX_KEY_SHIFT_L                       '1'        XK_1
+BX_KEY_1                                      '&'        XK_ampersand
+BX_KEY_1+BX_KEY_ALT_R                         '|'        XK_bar
+BX_KEY_2+BX_KEY_SHIFT_L                       '2'        XK_2
+BX_KEY_2+BX_KEY_ALT_R                         '@'        XK_at
+BX_KEY_2                                      'é'        XK_eacute
+BX_KEY_3+BX_KEY_SHIFT_L                       '3'        XK_3
+BX_KEY_3+BX_KEY_ALT_R                         '#'        XK_numbersign
+BX_KEY_3                                      '"'        XK_quotedbl
+BX_KEY_4+BX_KEY_SHIFT_L                       '4'        XK_4
+BX_KEY_4                                      apostrophe XK_apostrophe
+BX_KEY_5+BX_KEY_SHIFT_L                       '5'        XK_5
+BX_KEY_5                                      '('        XK_parenleft
+BX_KEY_6+BX_KEY_SHIFT_L                       '6'        XK_6
+BX_KEY_6+BX_KEY_ALT_R                         '^'        XK_asciicircum
+BX_KEY_6                                      '§'        XK_section
+BX_KEY_7+BX_KEY_SHIFT_L                       '7'        XK_7
+BX_KEY_7                                      'è'        XK_egrave
+BX_KEY_8+BX_KEY_SHIFT_L                       '8'        XK_8
+BX_KEY_8                                      '!'        XK_exclam
+BX_KEY_9+BX_KEY_SHIFT_L                       '9'        XK_9
+BX_KEY_9+BX_KEY_ALT_R                         '{'        XK_braceleft
+BX_KEY_9                                      'ç'        XK_ccedilla
+BX_KEY_A+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_A                                      'q'        XK_q
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_E+BX_KEY_ALT_R                         none       XK_EuroSign
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       '?'        XK_question
+BX_KEY_M                                      ','        XK_comma
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_Q                                      'a'        XK_a
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_W                                      'z'        XK_z
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_Z                                      'w'        XK_w
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              'µ'        XK_mu
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '£'        XK_sterling
+BX_KEY_BACKSLASH+BX_KEY_ALT_R                 '`'        XK_dead_grave
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   '.'        XK_period
+BX_KEY_COMMA                                  ';'        XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 '-'        XK_minus
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '_'        XK_underscore
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE                                  '²'        XK_twosuperior
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '³'        XK_threesuperior
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R            backslash  XK_backslash
+BX_KEY_LEFT_BRACKET                           none       XK_dead_circumflex
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            none       XK_dead_diaeresis
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_R              '['        XK_bracketleft
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '°'        XK_degree
+BX_KEY_MINUS                                  ')'        XK_parenright
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD                                 ':'        XK_colon
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  '/'        XK_slash
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET                          '$'        XK_dollar
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '*'        XK_asterisk
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             ']'        XK_bracketright
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'M'        XK_M
+BX_KEY_SEMICOLON                              'm'        XK_m
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '%'        XK_percent
+BX_KEY_SINGLE_QUOTE+BX_KEY_ALT_R              none       XK_dead_acute
+BX_KEY_SINGLE_QUOTE                           'ù'        XK_ugrave
+BX_KEY_SLASH                                  '='        XK_equal
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '+'        XK_plus
+BX_KEY_SLASH+BX_KEY_ALT_R                     none       XK_dead_tilde
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-da.map b/tools/ioemu/gui/keymaps/x11-pc-da.map
new file mode 100644 (file)
index 0000000..41ead2b
--- /dev/null
@@ -0,0 +1,247 @@
+# Bochs Keymap file
+# $Id: x11-pc-da.map,v 0.9 2002/09/02
+# Target: PC(x86) keyboard, DA keymap
+# Author: Andreas Ott
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_ALT_R                         '}'        XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L                       '='        XK_equal
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_1+BX_KEY_ALT_R                         '¡'        XK_exclamdown
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '='        XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R                         '@'        XK_at # XK_twosuperior
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '#'        XK_numbersign
+BX_KEY_3+BX_KEY_ALT_R                         '£'        XK_sterling
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '¤'        XK_currency
+BX_KEY_4+BX_KEY_ALT_R                         '$'        XK_dollar
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_ALT_R                         '½'        XK_onehalf
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R                         '¥'        XK_yen
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_ALT_R                         '{'        XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L                       '/'        XK_slash
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_ALT_R                         '['        XK_bracketleft
+BX_KEY_8+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_ALT_R                         ']'        XK_bracketright
+BX_KEY_9+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_A+BX_KEY_ALT_R                         'ª'        XK_ordfeminine
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_B+BX_KEY_ALT_R                         none       XK_rightdoublequotemark
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_C+BX_KEY_ALT_R                         '©'        XK_copyright
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_D+BX_KEY_ALT_R                         'ð'        XK_eth
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E+BX_KEY_ALT_R                         '?'        XK_EuroSign
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F+BX_KEY_ALT_R                         '?'        XK_dstroke
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G+BX_KEY_ALT_R                         '?'        XK_eng
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_H+BX_KEY_ALT_R                         '?'        XK_hstroke
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_I+BX_KEY_ALT_R                         none       XK_rightarrow
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_K+BX_KEY_ALT_R                         none       XK_kra
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_M+BX_KEY_ALT_R                         'µ'        XK_mu
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_O+BX_KEY_ALT_R                         none       XK_oslash
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_P+BX_KEY_ALT_R                         'þ'        XK_thorn
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_Q+BX_KEY_ALT_R                         '@'        XK_at
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R+BX_KEY_ALT_R                         '®'        XK_registered
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_S+BX_KEY_ALT_R                         'ß'        XK_ssharp
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_T+BX_KEY_ALT_R                         'þ'        XK_thorn
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U+BX_KEY_ALT_R                         none       XK_downarrow
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V+BX_KEY_ALT_R                         none       XK_leftdoublequotemark
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_W+BX_KEY_ALT_R                         '?'        XK_lstroke
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X+BX_KEY_ALT_R                         '»'        XK_guillemotright
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y+BX_KEY_ALT_R                         none       XK_leftarrow
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Z+BX_KEY_ALT_R                         '«'        XK_guillemotleft
+BX_KEY_Z                                      'z'        XK_z
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              apostrophe XK_apostrophe
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '*'        XK_asterisk
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_ALT_R                     none       XK_horizconnector
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   ';'        XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 none       XK_acute
+BX_KEY_EQUALS+BX_KEY_ALT_R                    '|'        XK_bar
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '`'        XK_grave
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE                                  '½'        XK_onehalf
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '§'        XK_section
+BX_KEY_GRAVE+BX_KEY_ALT_R                     '¾'        XK_threequarters
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R            backslash  XK_backslash
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            'Å'        XK_Aring
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_L              none       XK_diaeresis
+BX_KEY_LEFT_BRACKET                           'å'        XK_aring
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_R                     '±'        XK_plusminus
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_MINUS                                  '+'        XK_plus
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  ':'        XK_colon
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PERIOD+BX_KEY_ALT_R                    '·'        XK_periodcentered
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             '~'        XK_asciitilde
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '^'        XK_asciicircum
+BX_KEY_RIGHT_BRACKET                          '"'        XK_diaeresis
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'Æ'        XK_AE
+BX_KEY_SEMICOLON                              'æ'        XK_ae
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE                           'ø'        XK_oslash
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            'Ø'        XK_Ooblique
+BX_KEY_SLASH+BX_KEY_ALT_R                     '­'        XK_hyphen
+BX_KEY_SLASH                                  '-'        XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '_'        XK_underscore
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-de.map b/tools/ioemu/gui/keymaps/x11-pc-de.map
new file mode 100644 (file)
index 0000000..929ad06
--- /dev/null
@@ -0,0 +1,247 @@
+# Bochs Keymap file
+# $Id: x11-pc-de.map,v 1.7 2002/10/24 21:06:56 bdenney Exp $
+# Target: PC(x86) keyboard, DE keymap
+# Author: Volker Ruppert
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_ALT_R                         '}'        XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L                       '='        XK_equal
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_1+BX_KEY_ALT_R                         '¹'        XK_onesuperior
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '"'        XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R                         '²'        XK_twosuperior
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '§'        XK_section
+BX_KEY_3+BX_KEY_ALT_R                         '³'        XK_threesuperior
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        XK_dollar
+BX_KEY_4+BX_KEY_ALT_R                         '¼'        XK_onequarter
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_ALT_R                         '½'        XK_onehalf
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R                         '¾'        XK_threequarters
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_ALT_R                         '{'        XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L                       '/'        XK_slash
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_ALT_R                         '['        XK_bracketleft
+BX_KEY_8+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_ALT_R                         ']'        XK_bracketright
+BX_KEY_9+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_A+BX_KEY_ALT_R                         'æ'        XK_ae
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_B+BX_KEY_ALT_R                         none       XK_rightdoublequotemark
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_C+BX_KEY_ALT_R                         '¢'        XK_cent
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_D+BX_KEY_ALT_R                         'ð'        XK_eth
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E+BX_KEY_ALT_R                         none       XK_EuroSign
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F+BX_KEY_ALT_R                         none       XK_dstroke
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G+BX_KEY_ALT_R                         none       XK_eng
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_H+BX_KEY_ALT_R                         none       XK_hstroke
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_I+BX_KEY_ALT_R                         none       XK_rightarrow
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_K+BX_KEY_ALT_R                         none       XK_kra
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_M+BX_KEY_ALT_R                         'µ'        XK_mu
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_O+BX_KEY_ALT_R                         'ø'        XK_oslash
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_P+BX_KEY_ALT_R                         'þ'        XK_thorn
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_Q+BX_KEY_ALT_R                         '@'        XK_at
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R+BX_KEY_ALT_R                         '¶'        XK_paragraph
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_T+BX_KEY_ALT_R                         none       XK_tslash
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U+BX_KEY_ALT_R                         none       XK_downarrow
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V+BX_KEY_ALT_R                         none       XK_leftdoublequotemark
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_W+BX_KEY_ALT_R                         none       XK_lstroke
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X+BX_KEY_ALT_R                         '»'        XK_guillemotright
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Y+BX_KEY_ALT_R                         none       XK_leftarrow
+BX_KEY_Y                                      'z'        XK_z
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Z+BX_KEY_ALT_R                         '«'        XK_guillemotleft
+BX_KEY_Z                                      'y'        XK_y
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              apostrophe XK_apostrophe
+BX_KEY_BACKSLASH                              '#'        XK_numbersign
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_ALT_R                     none       XK_horizconnector
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   ';'        XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 none       XK_acute
+BX_KEY_EQUALS+BX_KEY_ALT_R                    '¸'        XK_cedilla
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '`'        XK_grave
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE                                  '^'        XK_asciicircum
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '°'        XK_degree
+BX_KEY_GRAVE+BX_KEY_ALT_R                     '¬'        XK_notsign
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R            '|'        XK_bar
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            'Ü'        XK_Udiaeresis
+BX_KEY_LEFT_BRACKET+BX_KEY_ALT_L              none       XK_diaeresis
+BX_KEY_LEFT_BRACKET                           'ü'        XK_udiaeresis
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_L                     backslash  XK_backslash
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_MINUS                                  'ß'        XK_ssharp
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  ':'        XK_colon
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PERIOD+BX_KEY_ALT_L                    '·'        XK_periodcentered
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             '~'        XK_asciitilde
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '*'        XK_asterisk
+BX_KEY_RIGHT_BRACKET                          '+'        XK_plus
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'Ö'        XK_Odiaeresis
+BX_KEY_SEMICOLON                              'ö'        XK_odiaeresis
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            'Ä'        XK_Adiaeresis
+BX_KEY_SINGLE_QUOTE                           'ä'        XK_adiaeresis
+BX_KEY_SLASH                                  none       XK_dead_belowdot
+BX_KEY_SLASH                                  '-'        XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '_'        XK_underscore
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-es.map b/tools/ioemu/gui/keymaps/x11-pc-es.map
new file mode 100644 (file)
index 0000000..3856044
--- /dev/null
@@ -0,0 +1,217 @@
+# Bochs Keymap file
+# $Id: x11-pc-es.map,v 1.4 2002/09/25 08:00:24 bdenney Exp $
+# Target: PC(x86) keyboard, ES keymap
+# Author: Vicente Hernando Ara 
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+BX_KEY_0                                      none       XK_0
+BX_KEY_0                                      none       XK_equal
+BX_KEY_1                                      none       XK_1
+BX_KEY_1                                      none       XK_bar
+BX_KEY_1                                      none       XK_exclam
+BX_KEY_2                                      none       XK_2
+BX_KEY_2                                      none       XK_at
+BX_KEY_2                                      none       XK_quotedbl
+BX_KEY_3                                      none       XK_3
+BX_KEY_3                                      none       XK_numbersign
+BX_KEY_3                                      none       XK_periodcentered
+BX_KEY_4                                      none       XK_4
+BX_KEY_4                                      none       XK_dollar
+BX_KEY_5                                      none       XK_5
+BX_KEY_5                                      none       XK_percent
+BX_KEY_6                                      none       XK_6
+BX_KEY_6                                      none       XK_ampersand
+BX_KEY_7                                      none       XK_7
+BX_KEY_7                                      none       XK_slash
+BX_KEY_8                                      none       XK_8
+BX_KEY_8                                      none       XK_parenleft
+BX_KEY_9                                      none       XK_9
+BX_KEY_9                                      none       XK_parenright
+BX_KEY_A                                      none       XK_A
+BX_KEY_A                                      none       XK_a
+BX_KEY_B                                      none       XK_B
+BX_KEY_B                                      none       XK_b
+BX_KEY_C                                      none       XK_C
+BX_KEY_C                                      none       XK_c
+BX_KEY_D                                      none       XK_D
+BX_KEY_D                                      none       XK_d
+BX_KEY_E                                      none       XK_E
+BX_KEY_E                                      none       XK_EuroSign
+BX_KEY_E                                      none       XK_e
+BX_KEY_F                                      none       XK_F
+BX_KEY_F                                      none       XK_f
+BX_KEY_G                                      none       XK_G
+BX_KEY_G                                      none       XK_g
+BX_KEY_H                                      none       XK_H
+BX_KEY_H                                      none       XK_h
+BX_KEY_I                                      none       XK_I
+BX_KEY_I                                      none       XK_i
+BX_KEY_J                                      none       XK_J
+BX_KEY_J                                      none       XK_j
+BX_KEY_K                                      none       XK_K
+BX_KEY_K                                      none       XK_k
+BX_KEY_L                                      none       XK_L
+BX_KEY_L                                      none       XK_l
+BX_KEY_M                                      none       XK_M
+BX_KEY_M                                      none       XK_m
+BX_KEY_N                                      none       XK_N
+BX_KEY_N                                      none       XK_n
+BX_KEY_O                                      none       XK_O
+BX_KEY_O                                      none       XK_o
+BX_KEY_P                                      none       XK_P
+BX_KEY_P                                      none       XK_p
+BX_KEY_Q                                      none       XK_Q
+BX_KEY_Q                                      none       XK_q
+BX_KEY_R                                      none       XK_R
+BX_KEY_R                                      none       XK_r
+BX_KEY_S                                      none       XK_S
+BX_KEY_S                                      none       XK_s
+BX_KEY_T                                      none       XK_T
+BX_KEY_T                                      none       XK_t
+BX_KEY_U                                      none       XK_U
+BX_KEY_U                                      none       XK_u
+BX_KEY_V                                      none       XK_V
+BX_KEY_V                                      none       XK_v
+BX_KEY_W                                      none       XK_W
+BX_KEY_W                                      none       XK_w
+BX_KEY_X                                      none       XK_X
+BX_KEY_X                                      none       XK_x
+BX_KEY_Y                                      none       XK_Y
+BX_KEY_Y                                      none       XK_y
+BX_KEY_Z                                      none       XK_Z
+BX_KEY_Z                                      none       XK_z
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              none       XK_Ccedilla
+BX_KEY_BACKSLASH                              none       XK_ccedilla
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  none       XK_comma
+BX_KEY_COMMA                                  none       XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  none       XK_Return
+BX_KEY_EQUALS                                 none       XK_exclamdown
+BX_KEY_EQUALS                                 none       XK_questiondown
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE                                  none       XK_asciitilde
+BX_KEY_GRAVE                                  none       XK_backslash
+BX_KEY_GRAVE                                  none       XK_grave
+BX_KEY_GRAVE                                  none       XK_masculine
+BX_KEY_GRAVE                                  none       XK_ordfeminine
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BACKSLASH                         none       XK_greater
+BX_KEY_LEFT_BACKSLASH                         none       XK_less
+BX_KEY_LEFT_BRACKET                           none       XK_braceleft
+BX_KEY_LEFT_BRACKET                           none       XK_bracketleft
+BX_KEY_LEFT_BRACKET                           none       XK_dead_circumflex
+BX_KEY_LEFT_BRACKET                           none       XK_dead_grave
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS                                  none       XK_apostrophe
+BX_KEY_MINUS                                  none       XK_question
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD                                 none       XK_colon
+BX_KEY_PERIOD                                 none       XK_period
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET                          none       XK_asterisk
+BX_KEY_RIGHT_BRACKET                          none       XK_braceright
+BX_KEY_RIGHT_BRACKET                          none       XK_bracketright
+BX_KEY_RIGHT_BRACKET                          none       XK_plus
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON                              none       XK_Ntilde
+BX_KEY_SEMICOLON                              none       XK_ntilde
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE                           none       XK_dead_acute
+BX_KEY_SINGLE_QUOTE                           none       XK_dead_diaeresis
+BX_KEY_SLASH                                  none       XK_minus
+BX_KEY_SLASH                                  none       XK_underscore
+BX_KEY_SPACE                                  none       XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    none       XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-fr.map b/tools/ioemu/gui/keymaps/x11-pc-fr.map
new file mode 100644 (file)
index 0000000..869b328
--- /dev/null
@@ -0,0 +1,218 @@
+# Bochs Keymap file
+# $Id: x11-pc-fr.map,v 1.5 2002/09/25 08:00:24 bdenney Exp $
+# Target: PC(x86) keyboard, FR keymap
+# Author: Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+
+BX_KEY_0+BX_KEY_SHIFT_L                       '0'        XK_0
+BX_KEY_0                                      'à'        XK_agrave
+BX_KEY_0+BX_KEY_ALT_R                         '@'        XK_at
+BX_KEY_1+BX_KEY_SHIFT_L                       '1'        XK_1
+BX_KEY_1                                      '&'        XK_ampersand
+BX_KEY_2+BX_KEY_SHIFT_L                       '2'        XK_2
+BX_KEY_2+BX_KEY_ALT_R                         '~'        XK_asciitilde
+BX_KEY_2                                      'é'        XK_eacute
+BX_KEY_3+BX_KEY_SHIFT_L                       '3'        XK_3
+BX_KEY_3+BX_KEY_ALT_R                         '#'        XK_numbersign
+BX_KEY_3                                      '"'        XK_quotedbl
+BX_KEY_4+BX_KEY_SHIFT_L                       '4'        XK_4
+BX_KEY_4                                      apostrophe XK_apostrophe
+BX_KEY_4+BX_KEY_ALT_R                         '{'        XK_braceleft
+BX_KEY_5+BX_KEY_SHIFT_L                       '5'        XK_5
+BX_KEY_5+BX_KEY_ALT_R                         '['        XK_bracketleft
+BX_KEY_5                                      '('        XK_parenleft
+BX_KEY_6+BX_KEY_SHIFT_L                       '6'        XK_6
+BX_KEY_6+BX_KEY_ALT_R                         '|'        XK_bar
+BX_KEY_6                                      '-'        XK_minus
+BX_KEY_7+BX_KEY_SHIFT_L                       '7'        XK_7
+BX_KEY_7                                      'è'        XK_egrave
+BX_KEY_7+BX_KEY_ALT_R                         '`'        XK_grave
+BX_KEY_8+BX_KEY_SHIFT_L                       '8'        XK_8
+BX_KEY_8+BX_KEY_ALT_R                         backslash  XK_backslash
+BX_KEY_8                                      '_'        XK_underscore
+BX_KEY_9+BX_KEY_SHIFT_L                       '9'        XK_9
+BX_KEY_9+BX_KEY_ALT_R                         '^'        XK_asciicircum
+BX_KEY_9                                      'ç'       XK_ccedilla
+BX_KEY_A+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_A                                      'q'        XK_q
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_E+BX_KEY_ALT_R                         none       XK_EuroSign
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       '?'        XK_question
+BX_KEY_M                                      ','        XK_comma
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_Q                                      'a'        XK_a
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_W                                      'z'        XK_z
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_Z                                      'w'        XK_w
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              '*'        XK_asterisk
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               'µ'        XK_mu
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   '.'        XK_period
+BX_KEY_COMMA                                  ';'        XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS+BX_KEY_ALT_R                    '}'        XK_braceright
+BX_KEY_EQUALS                                 '='        XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '+'        XK_plus
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE                                  '²'        XK_twosuperior
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_LEFT_BRACKET                           '^'        XK_dead_circumflex
+BX_KEY_LEFT_BRACKET                           none       XK_dead_diaeresis
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS+BX_KEY_ALT_R                     ']'        XK_bracketright
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '°'        XK_degree
+BX_KEY_MINUS                                  ')'        XK_parenright
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD                                 ':'        XK_colon
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  '/'        XK_slash
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             '¤'        XK_currency
+BX_KEY_RIGHT_BRACKET                          '$'        XK_dollar
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '£'        XK_sterling
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'M'        XK_M
+BX_KEY_SEMICOLON                              'm'        XK_m
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '%'        XK_percent
+BX_KEY_SINGLE_QUOTE                           'ù'        XK_ugrave
+BX_KEY_SLASH                                  '!'        XK_exclam
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '§'        XK_section
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-it.map b/tools/ioemu/gui/keymaps/x11-pc-it.map
new file mode 100644 (file)
index 0000000..fac365e
--- /dev/null
@@ -0,0 +1,207 @@
+# Bochs Keymap file
+# $Id: x11-pc-it.map,v 1.2 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, IT keymap
+# Author: Emanuele Goldoni
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       '='        XK_equal
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '"'        XK_quotedbl
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '£'        XK_sterling
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        XK_dollar
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '/'        XK_slash
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Z                                      'z'        XK_z
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              'ù'       XK_ugrave
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '§'        XK_section
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   ';'        XK_semicolon
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 'ì'       XK_igrave
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '^'        XK_asciicircum
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '|'        XK_bar
+BX_KEY_GRAVE                                  backslash  XK_backslash
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            'é'        XK_eacute
+BX_KEY_LEFT_BRACKET                           'è'        XK_egrave
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS                                  apostrophe XK_apostrophe
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  ':'        XK_colon
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '*'        XK_asterisk
+BX_KEY_RIGHT_BRACKET                          '+'        XK_plus
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'ç'        XK_ccedilla
+BX_KEY_SEMICOLON                              'ò'        XK_ograve
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE                           'à'         XK_agrave 
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '°'        XK_degree 
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '_'        XK_underscore
+BX_KEY_SLASH                                  '-'        XK_minus
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-se.map b/tools/ioemu/gui/keymaps/x11-pc-se.map
new file mode 100644 (file)
index 0000000..c564ca8
--- /dev/null
@@ -0,0 +1,278 @@
+# Bochs Keymap file
+# $Id: x11-pc-se.map,v 1.2 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, SE keymap
+# Author: Magnus 'Moggen' Öberg
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+# Upper key groups
+BX_KEY_ESC                                    none       XK_Escape
+
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+
+# Main key group
+#  Row 1
+BX_KEY_GRAVE                                  '§'        XK_section
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '½'        XK_onehalf
+BX_KEY_GRAVE+BX_KEY_ALT_R                     '¶'        XK_paragraph
+BX_KEY_GRAVE+BX_KEY_SHIFT_L+BX_KEY_ALT_R      '¾'        XK_threequarters
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_1+BX_KEY_ALT_R                         '¡'        XK_exclamdown
+BX_KEY_1+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '¹'        XK_onesuperior
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '"'        XK_quotedbl
+BX_KEY_2+BX_KEY_ALT_R                         '@'        XK_at
+BX_KEY_2+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '²'        XK_twosuperior
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '#'        XK_numbersign
+BX_KEY_3+BX_KEY_ALT_R                         '£'        XK_sterling
+BX_KEY_3+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '³'        XK_threesuperior
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '¤'        XK_currency
+BX_KEY_4+BX_KEY_ALT_R                         '$'        XK_dollar
+BX_KEY_4+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '¼'        XK_onequarter
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_5+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '¢'        XK_cent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_6+BX_KEY_ALT_R                         '¥'        XK_yen
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '/'        XK_slash
+BX_KEY_7+BX_KEY_ALT_R                         '{'        XK_braceleft
+BX_KEY_7+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '÷'        XK_division
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_8+BX_KEY_ALT_R                         '['        XK_bracketleft
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_9+BX_KEY_ALT_R                         ']'        XK_bracketright
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       '='        XK_equal
+BX_KEY_0+BX_KEY_ALT_R                         '}'        XK_braceright
+BX_KEY_0+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '°'        XK_degree
+BX_KEY_MINUS                                  '+'        XK_plus
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_MINUS+BX_KEY_ALT_L                     backslash  XK_backslash
+BX_KEY_MINUS+BX_KEY_SHIFT_L+BX_KEY_ALT_R      '¿'        XK_questiondown
+BX_KEY_EQUALS                                 none       XK_dead_acute
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  none       XK_dead_grave
+BX_KEY_EQUALS+BX_KEY_ALT_L                    '±'        XK_plusminus
+BX_KEY_EQUALS+BX_KEY_ALT_L+BX_KEY_ALT_R       '¬'        XK_notsign
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+
+#  Row 2
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E+BX_KEY_SHIFT_L+BX_KEY_ALT_R          none       XK_EuroSign
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R+BX_KEY_ALT_R                         '®'        XK_registered
+BX_KEY_T                                      't'        XK_t
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T+BX_KEY_ALT_R                         'þ'        XK_thorn
+BX_KEY_T+BX_KEY_SHIFT_L+BX_KEY_ALT_R          'Þ'        XK_THORN
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_LEFT_BRACKET                           'å'        XK_aring
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            'Å'        XK_Aring
+BX_KEY_RIGHT_BRACKET                          none       XK_dead_diaeresis
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           none       XK_dead_circumflex
+BX_KEY_RIGHT_BRACKET+BX_KEY_ALT_R             none       XK_dead_tilde
+BX_KEY_ENTER                                  return     XK_Return
+
+#  Row 3
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A+BX_KEY_ALT_R                         'ª'        XK_ordfeminine
+BX_KEY_A+BX_KEY_SHIFT_L+BX_KEY_ALT_R          'º'        XK_masculine
+BX_KEY_S                                      's'        XK_s
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S+BX_KEY_ALT_R                         'ß'        XK_ssharp
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D+BX_KEY_ALT_R                         'ð'        XK_eth
+BX_KEY_D+BX_KEY_SHIFT_L+BX_KEY_ALT_R          'Ð'        XK_ETH
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_SEMICOLON                              'ö'        XK_odiaeresis
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               'Ö'        XK_Odiaeresis
+BX_KEY_SEMICOLON+BX_KEY_ALT_R                 'ø'        XK_oslash
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L+BX_KEY_ALT_R  'Ø'        XK_Ooblique
+BX_KEY_SINGLE_QUOTE                           'ä'        XK_adiaeresis
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            'Ä'        XK_Adiaeresis
+BX_KEY_SINGLE_QUOTE+BX_KEY_ALT_R              'æ'        XK_ae
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L+BX_KEY_ALT_R 'Æ'      XK_AE
+BX_KEY_BACKSLASH                              apostrophe XK_apostrophe
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '*'        XK_asterisk
+BX_KEY_BACKSLASH+BX_KEY_ALT_R                 '´'        XK_acute
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L+BX_KEY_ALT_R  '×'        XK_multiply
+
+#  Row 4
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_LEFT_BACKSLASH                         '<'        XK_less
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '>'        XK_greater
+BX_KEY_LEFT_BACKSLASH+BX_KEY_ALT_R            '|'        XK_bar
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L+BX_KEY_ALT_R '¦'    XK_brokenbar
+BX_KEY_Z                                      'z'        XK_z
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Z+BX_KEY_ALT_R                         '«'        XK_guillemotleft
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X+BX_KEY_ALT_R                         '»'        XK_guillemotright
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C+BX_KEY_ALT_R                         '©'        XK_copyright
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V+BX_KEY_SHIFT_L+BX_KEY_ALT_R          '`'        XK_grave
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M+BX_KEY_ALT_R                         'µ'        XK_mu
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   ';'        XK_semicolon
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  ':'        XK_colon
+BX_KEY_PERIOD+BX_KEY_ALT_R                    '·'        XK_periodcentered
+BX_KEY_SLASH                                  '-'        XK_minus
+BX_KEY_SLASH+BX_KEY_SHIFT                     '_'        XK_underscore
+BX_KEY_SLASH+BX_KEY_ALT_R                     '­'        XK_hyphen
+BX_KEY_SLASH+BX_KEY_SHIFT+BX_KEY_ALT_R        '­'        XK_macron
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+
+#  Row 5
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_SPACE+BX_KEY_ALT_R                     none       XK_nobreakspace
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_WIN_R                                  none       XK_Super_R
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_CTRL_R                                 none       XK_Control_R
+
+# Ins/Del/Home/End/PgUp/PgDn
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_END                                    none       XK_End
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+
+# Arrow keys
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_DOWN                                   none       XK_Down
+
+# Numerical keypad
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
diff --git a/tools/ioemu/gui/keymaps/x11-pc-uk.map b/tools/ioemu/gui/keymaps/x11-pc-uk.map
new file mode 100644 (file)
index 0000000..05abbe4
--- /dev/null
@@ -0,0 +1,209 @@
+# Bochs Keymap file
+# $Id: x11-pc-uk.map,v 1.1 2002/12/11 21:35:50 bdenney Exp $
+# Target: PC(x86) keyboard, UK keymap
+# Author: Denis Lenihan
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '"'        XK_quotedbl
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '£'        XK_sterling
+BX_KEY_3+BX_KEY_ALT_R                        '|'        XK_EuroSign
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        XK_dollar
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '^'        XK_asciicircum
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_SHIFT_L                       '*'        XK_asterisk
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Z                                      'z'        XK_z
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_LEFT_BACKSLASH                         '\'       XK_backslash
+BX_KEY_LEFT_BACKSLASH+BX_KEY_SHIFT_L          '|'        XK_bar
+BX_KEY_BACKSLASH                             '~'        XK_asciitilde
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L              '#'        XK_numbersign
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   '<'        XK_less
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 '='        XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '+'        XK_plus
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '¬'        XK_notsign
+BX_KEY_GRAVE                                  '`'        XK_grave
+BX_KEY_GRAVE+BX_KEY_ALT_R                     '|'        XK_bar
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            '{'        XK_braceleft
+BX_KEY_LEFT_BRACKET                           '['        XK_bracketleft
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS                                  '-'        XK_minus
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '_'        XK_underscore
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  '>'        XK_greater
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '}'        XK_braceright
+BX_KEY_RIGHT_BRACKET                          ']'        XK_bracketright
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               ':'        XK_colon
+BX_KEY_SEMICOLON                              ';'        XK_semicolon
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE                           apostrophe XK_apostrophe
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '@'        XK_at
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_SLASH                                  '/'        XK_slash
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/keymaps/x11-pc-us.map b/tools/ioemu/gui/keymaps/x11-pc-us.map
new file mode 100644 (file)
index 0000000..8cda7a8
--- /dev/null
@@ -0,0 +1,205 @@
+# Bochs Keymap file
+# $Id: x11-pc-us.map,v 1.3 2002/09/25 08:00:25 bdenney Exp $
+# Target: PC(x86) keyboard, US keymap
+# Author: Christophe Bothamy, Bryce Denney
+#
+# The keymap file describes the layout of a keyboard, and how it translates
+# into Bochs key codes.
+#
+# Format:
+#  BX_Keysym                ASCII_equivalent      Xwin_Keysym
+#
+# Or, for keys that require modifiers:
+#  BX_Keysym+BX_Modifier    ASCII_equivalent    Xwin_Keysym
+#
+# BX_Keysym and BX_Modifier must be present in the bx_key_symbol[] list in
+# gui/keymap.cc.  The BX_Modifier is usually a shift key press, but it
+# could be any key.  Presently a maximum of one modifier is supported, but this
+# could be changed in keymap.h (structure def has only one slot for modifier),
+# keymap.cc (parsing code), and iodev/keyboard.cc (simulate keypresses for >1
+# modifier).
+#
+# The ASCII_equivalent must be either apostrophe + one character + apostrophe,
+# or one of these keywords: space, return, tab, backslash, apostrophe, none.
+# This format is designed to look like a char constant in C, but it's a very
+# simple parser.  There's no concept of backslash being an escape char.  The
+# backslash and apostrophe entries are provided for aesthetic purposes only: no
+# C++ programmer wants to see '\' or '''. The parser doesn't care, but they are
+# ugly.
+#
+# Xwin_Keysym is the X windows equivalent of the key combination.  These
+# codes should match whatever you find in /usr/X11R6/include/X11/keysymdef.h.
+# If you're running X windows, Bochs will take each of these Xwin_Keysyms,
+# pull off the XK_ in front, and use XStringToKeysym() to change them into
+# numerical codes.  If this lookup fails, you will get a panic and you need
+# to edit the keymap file.
+#
+
+BX_KEY_0                                      '0'        XK_0
+BX_KEY_0+BX_KEY_SHIFT_L                       ')'        XK_parenright
+BX_KEY_1                                      '1'        XK_1
+BX_KEY_1+BX_KEY_SHIFT_L                       '!'        XK_exclam
+BX_KEY_2                                      '2'        XK_2
+BX_KEY_2+BX_KEY_SHIFT_L                       '@'        XK_at
+BX_KEY_3                                      '3'        XK_3
+BX_KEY_3+BX_KEY_SHIFT_L                       '#'        XK_numbersign
+BX_KEY_4                                      '4'        XK_4
+BX_KEY_4+BX_KEY_SHIFT_L                       '$'        XK_dollar
+BX_KEY_5                                      '5'        XK_5
+BX_KEY_5+BX_KEY_SHIFT_L                       '%'        XK_percent
+BX_KEY_6                                      '6'        XK_6
+BX_KEY_6+BX_KEY_SHIFT_L                       '^'        XK_asciicircum
+BX_KEY_7                                      '7'        XK_7
+BX_KEY_7+BX_KEY_SHIFT_L                       '&'        XK_ampersand
+BX_KEY_8                                      '8'        XK_8
+BX_KEY_8+BX_KEY_SHIFT_L                       '*'        XK_asterisk
+BX_KEY_9                                      '9'        XK_9
+BX_KEY_9+BX_KEY_SHIFT_L                       '('        XK_parenleft
+BX_KEY_A+BX_KEY_SHIFT_L                       'A'        XK_A
+BX_KEY_A                                      'a'        XK_a
+BX_KEY_B+BX_KEY_SHIFT_L                       'B'        XK_B
+BX_KEY_B                                      'b'        XK_b
+BX_KEY_C+BX_KEY_SHIFT_L                       'C'        XK_C
+BX_KEY_C                                      'c'        XK_c
+BX_KEY_D+BX_KEY_SHIFT_L                       'D'        XK_D
+BX_KEY_D                                      'd'        XK_d
+BX_KEY_E+BX_KEY_SHIFT_L                       'E'        XK_E
+BX_KEY_E                                      'e'        XK_e
+BX_KEY_F+BX_KEY_SHIFT_L                       'F'        XK_F
+BX_KEY_F                                      'f'        XK_f
+BX_KEY_G+BX_KEY_SHIFT_L                       'G'        XK_G
+BX_KEY_G                                      'g'        XK_g
+BX_KEY_H+BX_KEY_SHIFT_L                       'H'        XK_H
+BX_KEY_H                                      'h'        XK_h
+BX_KEY_I+BX_KEY_SHIFT_L                       'I'        XK_I
+BX_KEY_I                                      'i'        XK_i
+BX_KEY_J+BX_KEY_SHIFT_L                       'J'        XK_J
+BX_KEY_J                                      'j'        XK_j
+BX_KEY_K+BX_KEY_SHIFT_L                       'K'        XK_K
+BX_KEY_K                                      'k'        XK_k
+BX_KEY_L+BX_KEY_SHIFT_L                       'L'        XK_L
+BX_KEY_L                                      'l'        XK_l
+BX_KEY_M+BX_KEY_SHIFT_L                       'M'        XK_M
+BX_KEY_M                                      'm'        XK_m
+BX_KEY_N+BX_KEY_SHIFT_L                       'N'        XK_N
+BX_KEY_N                                      'n'        XK_n
+BX_KEY_O+BX_KEY_SHIFT_L                       'O'        XK_O
+BX_KEY_O                                      'o'        XK_o
+BX_KEY_P+BX_KEY_SHIFT_L                       'P'        XK_P
+BX_KEY_P                                      'p'        XK_p
+BX_KEY_Q+BX_KEY_SHIFT_L                       'Q'        XK_Q
+BX_KEY_Q                                      'q'        XK_q
+BX_KEY_R+BX_KEY_SHIFT_L                       'R'        XK_R
+BX_KEY_R                                      'r'        XK_r
+BX_KEY_S+BX_KEY_SHIFT_L                       'S'        XK_S
+BX_KEY_S                                      's'        XK_s
+BX_KEY_T+BX_KEY_SHIFT_L                       'T'        XK_T
+BX_KEY_T                                      't'        XK_t
+BX_KEY_U+BX_KEY_SHIFT_L                       'U'        XK_U
+BX_KEY_U                                      'u'        XK_u
+BX_KEY_V+BX_KEY_SHIFT_L                       'V'        XK_V
+BX_KEY_V                                      'v'        XK_v
+BX_KEY_W+BX_KEY_SHIFT_L                       'W'        XK_W
+BX_KEY_W                                      'w'        XK_w
+BX_KEY_X+BX_KEY_SHIFT_L                       'X'        XK_X
+BX_KEY_X                                      'x'        XK_x
+BX_KEY_Y+BX_KEY_SHIFT_L                       'Y'        XK_Y
+BX_KEY_Y                                      'y'        XK_y
+BX_KEY_Z+BX_KEY_SHIFT_L                       'Z'        XK_Z
+BX_KEY_Z                                      'z'        XK_z
+BX_KEY_F1                                     none       XK_F1
+BX_KEY_F2                                     none       XK_F2
+BX_KEY_F3                                     none       XK_F3
+BX_KEY_F4                                     none       XK_F4
+BX_KEY_F5                                     none       XK_F5
+BX_KEY_F6                                     none       XK_F6
+BX_KEY_F7                                     none       XK_F7
+BX_KEY_F8                                     none       XK_F8
+BX_KEY_F9                                     none       XK_F9
+BX_KEY_F10                                    none       XK_F10
+BX_KEY_F11                                    none       XK_F11
+BX_KEY_F12                                    none       XK_F12
+BX_KEY_ALT_L                                  none       XK_Alt_L
+BX_KEY_ALT_L                                  none       XK_Meta_L
+BX_KEY_ALT_R                                  none       XK_Alt_R
+BX_KEY_ALT_R                                  none       XK_Mode_switch
+BX_KEY_ALT_R                                  none       XK_Multi_key
+BX_KEY_BACKSLASH                              backslash  XK_backslash
+BX_KEY_BACKSLASH+BX_KEY_SHIFT_L               '|'        XK_bar
+BX_KEY_BACKSPACE                              none       XK_BackSpace
+BX_KEY_CAPS_LOCK                              none       XK_Caps_Lock
+BX_KEY_COMMA                                  ','        XK_comma
+BX_KEY_COMMA+BX_KEY_SHIFT_L                   '<'        XK_less
+BX_KEY_CTRL_L                                 none       XK_Control_L
+BX_KEY_CTRL_R                                 none       XK_Control_R
+BX_KEY_DELETE                                 none       XK_Delete
+BX_KEY_DOWN                                   none       XK_Down
+BX_KEY_END                                    none       XK_End
+BX_KEY_ENTER                                  return     XK_Return
+BX_KEY_EQUALS                                 '='        XK_equal
+BX_KEY_EQUALS+BX_KEY_SHIFT_L                  '+'        XK_plus
+BX_KEY_ESC                                    none       XK_Escape
+BX_KEY_GRAVE+BX_KEY_SHIFT_L                   '~'        XK_asciitilde
+BX_KEY_GRAVE                                  '`'        XK_grave
+BX_KEY_HOME                                   none       XK_Home
+BX_KEY_INSERT                                 none       XK_Insert
+BX_KEY_KP_5                                   none       XK_KP_5
+BX_KEY_KP_5                                   none       XK_KP_Begin
+BX_KEY_KP_ADD                                 none       XK_KP_Add
+BX_KEY_KP_DELETE                              none       XK_KP_Decimal
+BX_KEY_KP_DELETE                              none       XK_KP_Delete
+BX_KEY_KP_DIVIDE                              none       XK_KP_Divide
+BX_KEY_KP_DOWN                                none       XK_KP_2
+BX_KEY_KP_DOWN                                none       XK_KP_Down
+BX_KEY_KP_END                                 none       XK_KP_1
+BX_KEY_KP_END                                 none       XK_KP_End
+BX_KEY_KP_ENTER                               none       XK_KP_Enter
+BX_KEY_KP_HOME                                none       XK_KP_7
+BX_KEY_KP_HOME                                none       XK_KP_Home
+BX_KEY_KP_INSERT                              none       XK_KP_0
+BX_KEY_KP_INSERT                              none       XK_KP_Insert
+BX_KEY_KP_LEFT                                none       XK_KP_4
+BX_KEY_KP_LEFT                                none       XK_KP_Left
+BX_KEY_KP_MULTIPLY                            none       XK_KP_Multiply
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_3
+BX_KEY_KP_PAGE_DOWN                           none       XK_KP_Page_Down
+BX_KEY_KP_PAGE_UP                             none       XK_KP_9
+BX_KEY_KP_PAGE_UP                             none       XK_KP_Page_Up
+BX_KEY_KP_RIGHT                               none       XK_KP_6
+BX_KEY_KP_RIGHT                               none       XK_KP_Right
+BX_KEY_KP_SUBTRACT                            none       XK_KP_Subtract
+BX_KEY_KP_UP                                  none       XK_KP_8
+BX_KEY_KP_UP                                  none       XK_KP_Up
+BX_KEY_LEFT                                   none       XK_Left
+BX_KEY_LEFT_BRACKET+BX_KEY_SHIFT_L            '{'        XK_braceleft
+BX_KEY_LEFT_BRACKET                           '['        XK_bracketleft
+BX_KEY_MENU                                   none       XK_Menu
+BX_KEY_MINUS                                  '-'        XK_minus
+BX_KEY_MINUS+BX_KEY_SHIFT_L                   '_'        XK_underscore
+BX_KEY_NUM_LOCK                               none       XK_Num_Lock
+BX_KEY_PAGE_DOWN                              none       XK_Page_Down
+BX_KEY_PAGE_UP                                none       XK_Page_Up
+BX_KEY_PAUSE                                  none       XK_Break
+BX_KEY_PAUSE                                  none       XK_Pause
+BX_KEY_PERIOD+BX_KEY_SHIFT_L                  '>'        XK_greater
+BX_KEY_PERIOD                                 '.'        XK_period
+BX_KEY_PRINT                                  none       XK_Print
+BX_KEY_PRINT                                  none       XK_Sys_Req
+BX_KEY_RIGHT                                  none       XK_Right
+BX_KEY_RIGHT_BRACKET+BX_KEY_SHIFT_L           '}'        XK_braceright
+BX_KEY_RIGHT_BRACKET                          ']'        XK_bracketright
+BX_KEY_SCRL_LOCK                              none       XK_Scroll_Lock
+BX_KEY_SEMICOLON+BX_KEY_SHIFT_L               ':'        XK_colon
+BX_KEY_SEMICOLON                              ';'        XK_semicolon
+BX_KEY_SHIFT_L                                none       XK_Shift_L
+BX_KEY_SHIFT_R                                none       XK_Shift_R
+BX_KEY_SINGLE_QUOTE                           apostrophe XK_apostrophe
+BX_KEY_SINGLE_QUOTE+BX_KEY_SHIFT_L            '"'        XK_quotedbl
+BX_KEY_SLASH+BX_KEY_SHIFT_L                   '?'        XK_question
+BX_KEY_SLASH                                  '/'        XK_slash
+BX_KEY_SPACE                                  space      XK_space
+BX_KEY_TAB                                    none       XK_ISO_Left_Tab
+BX_KEY_TAB                                    tab        XK_Tab
+BX_KEY_UP                                     none       XK_Up
+BX_KEY_WIN_L                                  none       XK_Super_L
+BX_KEY_WIN_R                                  none       XK_Super_R
diff --git a/tools/ioemu/gui/nogui.cc b/tools/ioemu/gui/nogui.cc
new file mode 100644 (file)
index 0000000..dd56d9d
--- /dev/null
@@ -0,0 +1,336 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: nogui.cc,v 1.21 2003/06/28 08:04:31 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#include "icon_bochs.h"
+
+class bx_nogui_gui_c : public bx_gui_c {
+public:
+  bx_nogui_gui_c (void) {}
+  DECLARE_GUI_VIRTUAL_METHODS()
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_nogui_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(nogui)
+
+#define LOG_THIS theGui->
+
+// This file defines stubs for the GUI interface, which is a
+// place to start if you want to port bochs to a platform, for
+// which there is no support for your native GUI, or if you want to compile
+// bochs without any native GUI support (no output window or
+// keyboard input will be possible).
+// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific
+// implementations of this interface.  -Kevin
+
+
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+//     specific options from the command line.  (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+//     only updated regions of the screen to the gui code to be redrawn.
+//     These define the dimensions of a region (tile).
+// headerbar_y:  A headerbar (toolbar) is display on the top of the
+//     VGA window, showing floppy status, and other information.  It
+//     always assumes the width of the current VGA mode width, but
+//     it's height is defined by this parameter.
+
+  void
+bx_nogui_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+                     unsigned headerbar_y)
+{
+  put("NGUI");
+  UNUSED(argc);
+  UNUSED(argv);
+  UNUSED(tilewidth);
+  UNUSED(tileheight);
+  UNUSED(headerbar_y);
+
+  UNUSED(bochs_icon_bits);  // global variable
+
+  if (bx_options.Oprivate_colormap->get ()) {
+    BX_INFO(("private_colormap option ignored."));
+    }
+}
+
+
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+  void
+bx_nogui_gui_c::handle_events(void)
+{
+}
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+  void
+bx_nogui_gui_c::flush(void)
+{
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared.  Don't
+// clear the area that defines the headerbar.
+
+  void
+bx_nogui_gui_c::clear_screen(void)
+{
+}
+
+
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+//           of the screen from the last call.  See below
+// new_text: array of character/attributes making up the current
+//           contents, which should now be displayed.  See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+//     This represents 80 characters wide by 25 high, with
+//     each character being 2 bytes.  The first by is the
+//     character value, the second is the attribute byte.
+//     I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+  void
+bx_nogui_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+                      unsigned long cursor_x, unsigned long cursor_y,
+                      bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+  UNUSED(old_text);
+  UNUSED(new_text);
+  UNUSED(cursor_x);
+  UNUSED(cursor_y);
+  UNUSED(tm_info);
+  UNUSED(nrows);
+}
+
+  int
+bx_nogui_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+  UNUSED(bytes);
+  UNUSED(nbytes);
+  return 0;
+}
+
+  int
+bx_nogui_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+  UNUSED(text_snapshot);
+  UNUSED(len);
+  return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+//          1=screen updated needed (redraw using current colormap)
+
+  bx_bool
+bx_nogui_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+  UNUSED(index);
+  UNUSED(red);
+  UNUSED(green);
+  UNUSED(blue);
+  return(0);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+//       dimension equal to the 'tilewidth' & 'tileheight' parameters to
+//       ::specific_init().  Each value specifies an index into the
+//       array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+//       left of the window.
+
+  void
+bx_nogui_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+  UNUSED(tile);
+  UNUSED(x0);
+  UNUSED(y0);
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+  void
+bx_nogui_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+  UNUSED(x);
+  UNUSED(y);
+  UNUSED(fheight);
+  UNUSED(fwidth);
+  UNUSED(bpp);
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar.  Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap.  The pixel order is:
+//       bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+  unsigned
+bx_nogui_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+  UNUSED(bmap);
+  UNUSED(xdim);
+  UNUSED(ydim);
+  return(0);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+//     ::create_bitmap().  'alignment' is either BX_GRAVITY_LEFT
+//     or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+//     meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+//     the boundaries of this bitmap.
+
+  unsigned
+bx_nogui_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+  UNUSED(bmap_id);
+  UNUSED(alignment);
+  UNUSED(f);
+  return(0);
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+  void
+bx_nogui_gui_c::show_headerbar(void)
+{
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'.  'bmap_id' will have
+// been generated by ::create_bitmap().  The old and new bitmap
+// must be of the same size.  This allows the bitmap the user
+// sees to change, when some action occurs.  For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+  void
+bx_nogui_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+  UNUSED(hbar_id);
+  UNUSED(bmap_id);
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+
+  void
+bx_nogui_gui_c::exit(void)
+{
+  BX_INFO(("bx_nogui_gui_c::exit() not implemented yet."));
+}
+
+  void
+bx_nogui_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
diff --git a/tools/ioemu/gui/rfb.cc b/tools/ioemu/gui/rfb.cc
new file mode 100644 (file)
index 0000000..f67f80e
--- /dev/null
@@ -0,0 +1,1508 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfb.cc,v 1.26.2.1 2004/02/02 22:35:30 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2000  Psyon.Org!
+//
+//    Donald Becker
+//    http://www.psyon.org
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_WITH_RFB
+
+#include "icon_bochs.h"
+#include "font/vga.bitmap.h"
+
+class bx_rfb_gui_c : public bx_gui_c {
+public:
+  bx_rfb_gui_c (void) {}
+  DECLARE_GUI_VIRTUAL_METHODS()
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_rfb_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(rfb)
+
+#define LOG_THIS theGui->
+
+#ifdef WIN32
+
+#include <winsock.h>
+#include <process.h>
+#include "rfb.h"
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <pthread.h>
+typedef unsigned long CARD32;
+typedef unsigned short CARD16;
+typedef short INT16;
+typedef unsigned char  CARD8;
+typedef int SOCKET;
+
+#endif
+
+#include "rfbproto.h"
+
+static bool keep_alive;
+static bool client_connected;
+
+#define BX_RFB_PORT_MIN 5900
+#define BX_RFB_PORT_MAX 5949
+static unsigned short rfbPort;
+
+// Headerbar stuff
+unsigned rfbBitmapCount = 0;
+struct {
+       char     *bmap;
+       unsigned xdim;
+       unsigned ydim;
+} rfbBitmaps[BX_MAX_PIXMAPS];
+
+unsigned rfbHeaderbarBitmapCount = 0;
+struct {
+       unsigned int index;
+       unsigned int xorigin;
+       unsigned int yorigin;
+       unsigned int alignment;
+       void (*f)(void);
+} rfbHeaderbarBitmaps[BX_MAX_HEADERBAR_ENTRIES];
+
+//Keyboard stuff
+#define KEYBOARD true
+#define MOUSE    false
+#define MAX_KEY_EVENTS 512
+struct {
+       bool type;
+       int  key;
+       int  down;
+       int  x;
+       int  y;
+} rfbKeyboardEvent[MAX_KEY_EVENTS];
+static unsigned long rfbKeyboardEvents = 0;
+static bool          bKeyboardInUse = false;
+
+// Misc Stuff
+struct {
+       unsigned int x;
+       unsigned int y;
+       unsigned int width;
+       unsigned int height;
+       bool updated;
+} rfbUpdateRegion;
+
+static char  *rfbScreen;
+static char  rfbPallet[256];
+
+static long  rfbDimensionX, rfbDimensionY;
+static long  rfbStretchedX, rfbStretchedY;
+static long  rfbHeaderbarY;
+static long  rfbTileX = 0;
+static long  rfbTileY = 0;
+static unsigned long  rfbCursorX = 0;
+static unsigned long  rfbCursorY = 0;
+static unsigned long  rfbOriginLeft  = 0;
+static unsigned long  rfbOriginRight = 0;
+
+static unsigned int text_rows=25, text_cols=80;
+static unsigned int font_height=16, font_width=8;
+
+//static unsigned long ServerThread   = 0;
+//static unsigned long ServerThreadID = 0;
+
+static SOCKET sGlobal;
+
+void ServerThreadInit(void *indata);
+void HandleRfbClient(SOCKET sClient);
+int  ReadExact(int sock, char *buf, int len);
+int  WriteExact(int sock, char *buf, int len);
+void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client);
+void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color);
+void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client);
+void SendUpdate(int x, int y, int width, int height);
+void StartThread();
+void rfbKeyPressed(Bit32u key, int press_release);
+void rfbMouseMove(int x, int y, int bmask);
+void DrawColorPallet();
+
+static const rfbPixelFormat BGR233Format = {
+    8, 8, 1, 1, 7, 7, 3, 0, 3, 6
+};
+
+// Set this for the endian of your machine. 0 = big, 1 = little 
+static const int rfbEndianTest = 1;
+
+#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
+#define Swap32(l) (((l) >> 24) | (((l) & 0x00ff0000) >> 8)  | (((l) & 0x0000ff00) << 8)  | ((l) << 24))
+#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s))
+#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l))
+#define PF_EQ(x,y) ((x.bitsPerPixel == y.bitsPerPixel) && (x.depth == y.depth) && (x.trueColour == y.trueColour) &&    ((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && (!x.trueColour || ((x.redMax == y.redMax) && (x.greenMax == y.greenMax) && (x.blueMax == y.blueMax) && (x.redShift == y.redShift) && (x.greenShift == y.greenShift) && (x.blueShift == y.blueShift))))
+
+// This file defines stubs for the GUI interface, which is a
+// place to start if you want to port bochs to a platform, for
+// which there is no support for your native GUI, or if you want to compile
+// bochs without any native GUI support (no output window or
+// keyboard input will be possible).
+// Look in 'x.cc', 'beos.cc', and 'win32.cc' for specific
+// implementations of this interface.  -Kevin
+
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+//     specific options from the command line.  (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+//     only updated regions of the screen to the gui code to be redrawn.
+//     These define the dimensions of a region (tile).
+// headerbar_y:  A headerbar (toolbar) is display on the top of the
+//     VGA window, showing floppy status, and other information.  It
+//     always assumes the width of the current VGA mode width, but
+//     it's height is defined by this parameter.
+
+void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight, unsigned headerbar_y)
+{
+  unsigned char fc, vc;
+
+  put("RFB");
+  UNUSED(bochs_icon_bits);
+
+  // the ask menu doesn't work on the client side
+  io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
+
+  rfbHeaderbarY = headerbar_y;
+  rfbDimensionX = 640;
+  rfbDimensionY = 480 + rfbHeaderbarY;
+  rfbStretchedX = rfbDimensionX;
+  rfbStretchedY = rfbDimensionY;
+  rfbTileX      = tilewidth;
+  rfbTileY      = tileheight;
+
+  for(int i = 0; i < 256; i++) {
+    for(int j = 0; j < 16; j++) {
+      vc = bx_vgafont[i].data[j];
+      fc = 0;
+      for (int b = 0; b < 8; b++) {
+        fc |= (vc & 0x01) << (7 - b);
+        vc >>= 1;
+      }
+      vga_charmap[i*32+j] = fc;
+    }
+  }
+
+  rfbScreen = (char *)malloc(rfbDimensionX * rfbDimensionY); 
+  memset(&rfbPallet, 0, sizeof(rfbPallet));
+  rfbPallet[63] = (char)0xFF;
+
+  rfbUpdateRegion.x = rfbDimensionX;
+  rfbUpdateRegion.y = rfbDimensionY;
+  rfbUpdateRegion.width  = 0;
+  rfbUpdateRegion.height = 0;
+  rfbUpdateRegion.updated = false;
+
+  keep_alive = true;
+  client_connected = false;
+  StartThread();
+
+#ifdef WIN32
+  Sleep(1000);
+  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+#endif
+  if (bx_options.Oprivate_colormap->get ()) {
+    BX_ERROR(( "private_colormap option ignored." ));
+  }
+  int counter = 30;
+  while ((!client_connected) && (counter--)) {
+#ifdef WIN32
+    Sleep(1000);
+#else
+    sleep(1);
+#endif
+  }
+  if (counter < 0) BX_PANIC(("timeout! no client present"));
+}
+
+bool InitWinsock()
+{
+#ifdef WIN32
+       WSADATA wsaData;
+       if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false;
+#endif
+       return true;
+}
+
+bool StopWinsock()
+{
+#ifdef WIN32
+       WSACleanup();
+#endif
+       return true;
+}
+
+void ServerThreadInit(void *indata) 
+{
+       SOCKET             sServer;
+       SOCKET             sClient;
+       struct sockaddr_in sai;
+       unsigned int       sai_size;
+       int port_ok = 0;
+
+#ifdef WIN32
+       SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
+#endif
+       if(!InitWinsock()) {
+               BX_PANIC(( "could not initialize winsock."));
+               goto end_of_thread;
+       }
+
+       sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if(sServer == -1) { 
+               BX_PANIC(( "could not create socket." ));
+               goto end_of_thread;
+       }
+       for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) {
+         sai.sin_addr.s_addr = INADDR_ANY;
+         sai.sin_family      = AF_INET;
+         sai.sin_port        = htons(rfbPort);
+         BX_INFO (("Trying port %d", rfbPort));
+         if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) {
+                 BX_INFO(( "Could not bind socket."));
+                 continue;
+         }
+         if(listen(sServer, SOMAXCONN) == -1) {
+                 BX_INFO(( "Could not listen on socket."));
+                 continue;
+         }
+         // success
+         port_ok = 1;
+         break;
+       }
+       if (!port_ok) {
+         BX_PANIC (("RFB could not bind any port between %d and %d\n", 
+               BX_RFB_PORT_MIN,
+               BX_RFB_PORT_MAX));
+         goto end_of_thread;
+       }
+       BX_INFO (("listening for connections on port %i", rfbPort));
+       fprintf (stderr, "RFB: listening for connections on port %i\n", rfbPort);
+       sai_size = sizeof(sai);
+       while(keep_alive) {
+               sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size);
+               if(sClient != -1) {
+                       HandleRfbClient(sClient);
+                       sGlobal = -1;
+                       close(sClient);
+               } else {
+                       close(sClient);
+               }
+       }
+
+end_of_thread:
+       StopWinsock();
+}
+
+void HandleRfbClient(SOCKET sClient) 
+{
+       char rfbName[] = "Bochs-RFB";
+       rfbProtocolVersionMsg pv;
+       int one = 1;
+       CARD32 auth;
+       rfbClientInitMsg cim;
+       rfbServerInitMsg sim;
+
+       client_connected = true;
+       setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
+       fprintf(stderr, "# RFB: accepted client connection.\n");
+       sprintf(pv, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+
+       if(WriteExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could not send protocol version.\n");
+               return;
+       }
+       if(ReadExact(sClient, pv, sz_rfbProtocolVersionMsg) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could not recieve client protocol version.\n");
+               return;
+       }
+
+       auth = Swap32IfLE(rfbNoAuth);
+       if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could not send authorization method.\n");
+               return;
+       }
+
+       if(ReadExact(sClient, (char *)&cim, sz_rfbClientInitMsg) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could not recieve client initialization message.\n");
+               return;
+       }
+
+       sim.framebufferWidth  = Swap16IfLE((short)rfbDimensionX);
+       sim.framebufferHeight = Swap16IfLE((short)rfbDimensionY);
+       sim.format            = BGR233Format;
+       sim.format.redMax     = Swap16IfLE(sim.format.redMax);
+       sim.format.greenMax   = Swap16IfLE(sim.format.greenMax);
+       sim.format.blueMax    = Swap16IfLE(sim.format.blueMax);
+       sim.nameLength = strlen(rfbName);
+       sim.nameLength = Swap32IfLE(sim.nameLength);
+       if(WriteExact(sClient, (char *)&sim, sz_rfbServerInitMsg) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could send server initialization message.\n");
+               return;
+       }
+       if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) {
+               fprintf(stderr, "# ERROR: RFB: could not send server name.\n");
+               return;
+       }
+
+       sGlobal = sClient;
+       while(keep_alive) {
+               CARD8 msgType;
+               int n;
+
+               if((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) {
+                       if(n == 0) {
+                               fprintf(stderr, "# RFB: client closed connection.\n");
+                       } else {
+                               fprintf(stderr, "# RFB: error recieving data.\n");
+                       }
+                       return;
+               }
+               
+               switch(msgType) {
+               case rfbSetPixelFormat:
+                       {
+                               rfbSetPixelFormatMsg spf;
+                               ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMsg));
+
+                               spf.format.bitsPerPixel = spf.format.bitsPerPixel;
+                               spf.format.depth = spf.format.depth;
+                               spf.format.trueColour = (spf.format.trueColour ? 1 : 0);
+                               spf.format.bigEndian = (spf.format.bigEndian ? 1 : 0);
+                               spf.format.redMax = Swap16IfLE(spf.format.redMax);
+                               spf.format.greenMax = Swap16IfLE(spf.format.greenMax);
+                               spf.format.blueMax = Swap16IfLE(spf.format.blueMax);
+                               spf.format.redShift = spf.format.redShift;
+                               spf.format.greenShift = spf.format.greenShift;
+                               spf.format.blueShift = spf.format.blueShift;
+                               
+                               if (!PF_EQ(spf.format, BGR233Format)) {
+                                       fprintf(stderr,"# ERROR: RFB: client has wrong pixel format\n");
+                                       //return;
+                               }
+                               break;
+                       }
+               case rfbFixColourMapEntries:
+                       {
+                               rfbFixColourMapEntriesMsg fcme;
+                               ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMsg));
+                               break;
+                       }
+               case rfbSetEncodings:
+                       {
+                               rfbSetEncodingsMsg se;
+                               int                i;
+                               CARD32             enc;
+                               ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMsg));
+                               se.nEncodings = Swap16IfLE(se.nEncodings);
+                               for(i = 0; i < se.nEncodings; i++) {
+                                       if((n = ReadExact(sClient, (char *)&enc, sizeof(CARD32))) <= 0) {
+                                               if(n == 0) {
+                                                       fprintf(stderr, "# RFB: client closed connection.\n");
+                                               } else {
+                                                       fprintf(stderr, "# RFB: error recieving data.\n");
+                                               }
+                                               return;
+                                       }
+                               }
+                               break;
+                       }
+               case rfbFramebufferUpdateRequest:
+                       {
+                               rfbFramebufferUpdateRequestMsg fur;
+
+                               ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMsg));
+                               if(!fur.incremental) {
+                                       rfbUpdateRegion.x = 0;
+                                       rfbUpdateRegion.y = 0;
+                                       rfbUpdateRegion.width  = rfbDimensionX;
+                                       rfbUpdateRegion.height = rfbDimensionY;
+                                       rfbUpdateRegion.updated = true;
+                               } //else {
+                               //      if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x;
+                               //      if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y;
+                               //      if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x);
+                               //      if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y);
+                               //}
+                               //rfbUpdateRegion.updated = true;
+                               break;
+                       }
+               case rfbKeyEvent:
+                       {
+                               rfbKeyEventMsg ke;
+                               ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMsg));
+                               ke.key = Swap32IfLE(ke.key);
+                               while(bKeyboardInUse);
+                               bKeyboardInUse = true;
+                               if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
+                               rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD;
+                               rfbKeyboardEvent[rfbKeyboardEvents].key  = ke.key;
+                               rfbKeyboardEvent[rfbKeyboardEvents].down = ke.down;
+                               rfbKeyboardEvents++;
+                               bKeyboardInUse = false;
+                               break;
+                       }
+               case rfbPointerEvent:
+                       {       
+                               rfbPointerEventMsg pe;
+                               ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMsg));
+                               while(bKeyboardInUse);
+                               bKeyboardInUse = true;
+                               if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
+                               rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE;
+                               rfbKeyboardEvent[rfbKeyboardEvents].x    = Swap16IfLE(pe.x);
+                               rfbKeyboardEvent[rfbKeyboardEvents].y    = Swap16IfLE(pe.y);
+                               rfbKeyboardEvent[rfbKeyboardEvents].down = pe.buttonMask;
+                               rfbKeyboardEvents++;
+                               bKeyboardInUse = false;
+                               break;
+                       }
+               case rfbClientCutText:
+                       {
+                               rfbClientCutTextMsg cct;
+                               ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMsg));
+                               break;
+                       }
+               }
+       }
+}
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+void bx_rfb_gui_c::handle_events(void)
+{
+       unsigned int i = 0;
+       while(bKeyboardInUse);
+       bKeyboardInUse = true;
+       if(rfbKeyboardEvents > 0) {
+               for(i = 0; i < rfbKeyboardEvents; i++) {
+                       if(rfbKeyboardEvent[i].type == KEYBOARD) {
+                               rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down);
+                       } else { //type == MOUSE;
+                               rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].down);
+                       }
+               }
+               rfbKeyboardEvents = 0;
+       }
+       bKeyboardInUse = false;
+
+       if(rfbUpdateRegion.updated) {
+               SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width, rfbUpdateRegion.height);
+               rfbUpdateRegion.x = rfbDimensionX;
+               rfbUpdateRegion.y = rfbDimensionY;
+               rfbUpdateRegion.width  = 0;
+               rfbUpdateRegion.height = 0;
+       }
+       rfbUpdateRegion.updated = false;
+}
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+void bx_rfb_gui_c::flush(void)
+{
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared.  Don't
+// clear the area that defines the headerbar.
+void bx_rfb_gui_c::clear_screen(void)
+{
+       memset(&rfbScreen[rfbDimensionX * rfbHeaderbarY], 0, rfbDimensionX * (rfbDimensionY - rfbHeaderbarY));
+}
+
+
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+//           of the screen from the last call.  See below
+// new_text: array of character/attributes making up the current
+//           contents, which should now be displayed.  See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+//     This represents 80 characters wide by 25 high, with
+//     each character being 2 bytes.  The first by is the
+//     character value, the second is the attribute byte.
+//     I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+void bx_rfb_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+  unsigned char *old_line, *new_line;
+  unsigned char cAttr, cChar;
+  unsigned int  curs, hchars, offset, rows, x, y, xc, yc;
+  bx_bool force_update=0;
+
+  UNUSED(nrows);
+
+  if(charmap_updated) {
+    force_update = 1;
+    charmap_updated = 0;
+  }
+
+  // first invalidate character at previous and new cursor location
+  if ( (rfbCursorY < text_rows) && (rfbCursorX < text_cols) ) {
+    curs = rfbCursorY * tm_info.line_offset + rfbCursorX * 2;
+    old_text[curs] = ~new_text[curs];
+  }
+  if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
+     (cursor_y < text_rows) && (cursor_x < text_cols)) {
+    curs = cursor_y * tm_info.line_offset + cursor_x * 2;
+    old_text[curs] = ~new_text[curs];
+  } else {
+    curs = 0xffff;
+  }
+
+  rows = text_rows;
+  y = 0;
+  do {
+    hchars = text_cols;
+    new_line = new_text;
+    old_line = old_text;
+    offset = y * tm_info.line_offset;
+    yc = y * font_height + rfbHeaderbarY;
+    x = 0;
+    do {
+      if (force_update || (old_text[0] != new_text[0])
+          || (old_text[1] != new_text[1])) {
+        cChar = new_text[0];
+        cAttr = new_text[1];
+        xc = x * 8;
+        DrawChar(xc, yc, 8, font_height, 0, (char *)&vga_charmap[cChar<<5], cAttr);
+        if(yc < rfbUpdateRegion.y) rfbUpdateRegion.y = yc;
+        if((yc + font_height - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = (yc + font_height - rfbUpdateRegion.y);
+        if(xc < rfbUpdateRegion.x) rfbUpdateRegion.x = xc;
+        if((xc + 8 - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = (xc + 8 - rfbUpdateRegion.x);
+        rfbUpdateRegion.updated = true;
+       if (offset == curs) {
+          cAttr = ((cAttr >> 4) & 0xF) + ((cAttr & 0xF) << 4);
+          DrawChar(xc, yc + tm_info.cs_start, 8, tm_info.cs_end - tm_info.cs_start + 1,
+                   tm_info.cs_start, (char *)&vga_charmap[cChar<<5], cAttr);
+        }
+      }
+      x++;
+      new_text+=2;
+      old_text+=2;
+      offset+=2;
+    } while (--hchars);
+    y++;
+    new_text = new_line + tm_info.line_offset;
+    old_text = old_line + tm_info.line_offset;
+  } while (--rows);
+
+  rfbCursorX = cursor_x;
+  rfbCursorY = cursor_y;
+}
+
+  int
+bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+  return 0;
+}
+
+  int
+bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+  return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+//          1=screen updated needed (redraw using current colormap)
+
+bx_bool bx_rfb_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+       rfbPallet[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6);
+       return(1);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+//       dimension equal to the 'tilewidth' & 'tileheight' parameters to
+//       ::specific_init().  Each value specifies an index into the
+//       array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+//       left of the window.
+void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+       UpdateScreen(tile, x0, y0 + rfbHeaderbarY, rfbTileX, rfbTileY, false);
+       if(x0 < rfbUpdateRegion.x) rfbUpdateRegion.x = x0;
+       if((y0 + rfbHeaderbarY) < rfbUpdateRegion.y) rfbUpdateRegion.y = y0 + rfbHeaderbarY;
+       if(((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height =  ((y0 + rfbHeaderbarY + rfbTileY) - rfbUpdateRegion.y);
+       if(((x0 + rfbTileX) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((x0 + rfbTileX) - rfbUpdateRegion.x);
+       rfbUpdateRegion.updated = true;
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+  void
+bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+  if (bpp > 8) {
+    BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
+  }
+  if (fheight > 0) {
+    font_height = fheight;
+    font_width = fwidth;
+    text_cols = x / fwidth;
+    text_rows = y / fheight;
+  } else {
+    if ((x > 640) || (y > 480)) {
+      BX_PANIC(("dimension_update(): RFB doesn't support graphics modes > 640x480 (%dx%d)", x, y));
+    }
+  }
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar.  Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap.  The pixel order is:
+//       bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+       if(rfbBitmapCount >= BX_MAX_PIXMAPS) {
+               fprintf(stderr, "# RFB: too many pixmaps.\n");
+               return 0;
+       }
+       rfbBitmaps[rfbBitmapCount].bmap = (char *)malloc((xdim * ydim) / 8);
+       rfbBitmaps[rfbBitmapCount].xdim = xdim;
+       rfbBitmaps[rfbBitmapCount].ydim = ydim;
+       memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8);
+       
+       rfbBitmapCount++;
+       return(rfbBitmapCount - 1);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+//     ::create_bitmap().  'alignment' is either BX_GRAVITY_LEFT
+//     or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+//     meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+//     the boundaries of this bitmap.
+
+unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+       int hb_index;
+
+       if((rfbHeaderbarBitmapCount + 1) > BX_MAX_HEADERBAR_ENTRIES) {
+               return 0;
+       }
+
+       rfbHeaderbarBitmapCount++;
+       hb_index = rfbHeaderbarBitmapCount - 1;
+       rfbHeaderbarBitmaps[hb_index].index     = bmap_id;
+       rfbHeaderbarBitmaps[hb_index].alignment = alignment;
+       rfbHeaderbarBitmaps[hb_index].f = f;
+       if (alignment == BX_GRAVITY_LEFT) {
+               rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginLeft;
+               rfbHeaderbarBitmaps[hb_index].yorigin = 0;
+               rfbOriginLeft += rfbBitmaps[bmap_id].xdim;
+       } else { // BX_GRAVITY_RIGHT
+               rfbOriginRight += rfbBitmaps[bmap_id].xdim;
+               rfbHeaderbarBitmaps[hb_index].xorigin = rfbOriginRight;
+               rfbHeaderbarBitmaps[hb_index].yorigin = 0;
+       }
+       return hb_index;
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+void bx_rfb_gui_c::show_headerbar(void)
+{
+  char *newBits;
+  unsigned int i, xorigin;
+
+  newBits = (char *)malloc(rfbDimensionX * rfbHeaderbarY);
+  memset(newBits, 0, (rfbDimensionX * rfbHeaderbarY));
+  DrawBitmap(0, 0, rfbDimensionX, rfbHeaderbarY, newBits, (char)0xf0, false);
+  for(i = 0; i < rfbHeaderbarBitmapCount; i++) {
+    if(rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT) {
+      xorigin = rfbHeaderbarBitmaps[i].xorigin;
+    } else {
+      xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin;
+    }
+    DrawBitmap(xorigin, 0, rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].ydim, rfbBitmaps[rfbHeaderbarBitmaps[i].index].bmap, (char)0xf0, false);
+  }
+  free(newBits);
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'.  'bmap_id' will have
+// been generated by ::create_bitmap().  The old and new bitmap
+// must be of the same size.  This allows the bitmap the user
+// sees to change, when some action occurs.  For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+       rfbHeaderbarBitmaps[hbar_id].index = bmap_id;
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+void bx_rfb_gui_c::exit(void)
+{
+       unsigned int i;
+       keep_alive = false;
+       StopWinsock();
+       free(rfbScreen);
+       for(i = 0; i < rfbBitmapCount; i++) {
+               free(rfbBitmaps[i].bmap);
+       }
+       fprintf(stderr, "# RFB: bx_rfb_gui_c::exit()\n");
+}
+
+/*
+* ReadExact reads an exact number of bytes on a TCP socket.  Returns 1 if
+* those bytes have been read, 0 if the other end has closed, or -1 if an error
+* occurred (errno is set to ETIMEDOUT if it timed out).
+*/
+
+int ReadExact(int sock, char *buf, int len)
+{
+    int n;
+    while (len > 0) {
+       n = recv(sock, buf, len, 0);
+       if (n > 0) {
+           buf += n;
+           len -= n;
+        } else {
+            return n;
+       }
+    }
+    return 1;
+}
+
+/*
+* WriteExact writes an exact number of bytes on a TCP socket.  Returns 1 if
+* those bytes have been written, or -1 if an error occurred (errno is set to
+* ETIMEDOUT if it timed out).
+*/
+
+int WriteExact(int sock, char *buf, int len)
+{
+    int n;
+       
+    while (len > 0) {
+       n = send(sock, buf, len,0);
+               
+       if (n > 0) {
+           buf += n;
+           len -= n;
+       } else if (n == 0) {
+           fprintf(stderr,"WriteExact: write returned 0?\n");
+           return n;
+        } else {
+            return n;
+       }
+    }
+    return 1;
+}
+
+void DrawBitmap(int x, int y, int width, int height, char *bmap, char color, bool update_client)
+{
+       int  i;
+       unsigned char *newBits;
+       char fgcolor, bgcolor;
+       char vgaPallet[] = { (char)0x00, //Black 
+                                                (char)0x01, //Dark Blue
+                                                (char)0x02, //Dark Green
+                                                (char)0x03, //Dark Cyan
+                                                (char)0x04, //Dark Red
+                                                (char)0x05, //Dark Magenta
+                                                (char)0x06, //Brown
+                                                (char)0x07, //Light Gray
+                                                (char)0x38, //Dark Gray
+                                                (char)0x09, //Light Blue
+                                                (char)0x12, //Green
+                                                (char)0x1B, //Cyan
+                                                (char)0x24, //Light Red
+                                                (char)0x2D, //Magenta
+                                                (char)0x36, //Yellow
+                                                (char)0x3F  //White
+                                               };
+
+       bgcolor = vgaPallet[(color >> 4) & 0xF];
+       fgcolor = vgaPallet[color & 0xF];
+       newBits = (unsigned char *)malloc(width * height);
+       memset(newBits, 0, (width * height));
+       for(i = 0; i < (width * height) / 8; i++) {
+               newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor;
+               newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor;
+               newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor;
+               newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor;
+               newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor;
+               newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor;
+               newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor;
+               newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor;
+       }
+       UpdateScreen(newBits, x, y, width, height, update_client);
+       //DrawColorPallet();
+       free(newBits);
+}
+
+void DrawChar(int x, int y, int width, int height, int fonty, char *bmap, char color)
+{
+  static unsigned char newBits[8 * 32];
+  unsigned char mask;
+  int bytes = width * height;
+  char fgcolor, bgcolor;
+  char vgaPallet[] = { (char)0x00, //Black
+                       (char)0x01, //Dark Blue
+                       (char)0x02, //Dark Green
+                       (char)0x03, //Dark Cyan
+                       (char)0x04, //Dark Red
+                       (char)0x05, //Dark Magenta
+                       (char)0x06, //Brown
+                       (char)0x07, //Light Gray
+                       (char)0x38, //Dark Gray
+                       (char)0x09, //Light Blue
+                       (char)0x12, //Green
+                       (char)0x1B, //Cyan
+                       (char)0x24, //Light Red
+                       (char)0x2D, //Magenta
+                       (char)0x36, //Yellow
+                       (char)0x3F  //White
+                     };
+
+  bgcolor = vgaPallet[(color >> 4) & 0xF];
+  fgcolor = vgaPallet[color & 0xF];
+
+  for(int i = 0; i < bytes; i+=width) {
+    mask = 0x80;
+    for(int j = 0; j < width; j++) {
+      newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
+      mask >>= 1;
+    }
+    fonty++;
+  }
+  UpdateScreen(newBits, x, y, width, height, false);
+  //DrawColorPallet();
+}
+
+void DrawColorPallet()
+{
+       unsigned char bits[100];
+       int x = 0, y = 0, c;
+       for(c = 0; c < 256; c++) {
+               memset(&bits, rfbPallet[c], 100);
+               UpdateScreen(bits, x, y, 10, 10, false);
+               x += 10;
+               if(x > 70) {
+                       y += 10;
+                       x = 0;
+               }
+       }
+}
+
+void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height, bool update_client)
+{
+       int i, c;
+       for(i = 0; i < height; i++) {
+               for(c = 0; c < width; c++) {
+                       newBits[(i * width) + c] = rfbPallet[newBits[(i * width) + c]];
+               }
+               memcpy(&rfbScreen[y * rfbDimensionX + x], &newBits[i * width], width);
+               y++;
+       }
+       if(update_client) {
+               if(sGlobal == -1) return;
+               rfbFramebufferUpdateMsg fum;
+               rfbFramebufferUpdateRectHeader furh;
+               fum.type = rfbFramebufferUpdate;
+               fum.nRects = Swap16IfLE(1);
+               WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg);
+               furh.r.x = Swap16IfLE(x);
+               furh.r.y = Swap16IfLE((y - i));
+               furh.r.w = Swap16IfLE((short)width);
+               furh.r.h = Swap16IfLE((short)height);
+               furh.encoding = Swap32IfLE(rfbEncodingRaw);
+               WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader);
+               WriteExact(sGlobal, (char *)newBits, width * height);
+       }
+}
+
+void SendUpdate(int x, int y, int width, int height)
+{
+       char *newBits;
+       int  i;
+
+       if(x < 0 || y < 0 || (x + width) > rfbDimensionX || (y + height) > rfbDimensionY) {
+               fprintf(stderr, "# RFB: Dimensions out of bounds.  x=%i y=%i w=%i h=%i\n", x, y, width, height);
+       }
+       if(sGlobal != -1) {
+               rfbFramebufferUpdateMsg fum;
+               rfbFramebufferUpdateRectHeader furh;
+
+               fum.type = rfbFramebufferUpdate;
+               fum.nRects = Swap16IfLE(1);
+
+               furh.r.x = Swap16IfLE(x);
+               furh.r.y = Swap16IfLE(y);
+               furh.r.w = Swap16IfLE((short)width);
+               furh.r.h = Swap16IfLE((short)height);
+               furh.encoding = Swap32IfLE(rfbEncodingRaw);
+
+               newBits = (char *)malloc(width * height);
+               for(i = 0; i < height; i++) {
+                       memcpy(&newBits[i * width], &rfbScreen[y * rfbDimensionX + x], width);
+                       y++;
+               }
+
+               WriteExact(sGlobal, (char *)&fum, sz_rfbFramebufferUpdateMsg);
+               WriteExact(sGlobal, (char *)&furh, sz_rfbFramebufferUpdateRectHeader);
+               WriteExact(sGlobal, (char *)newBits, width * height);
+
+               free(newBits);
+       }
+}
+
+void StartThread()
+{
+#ifdef WIN32
+       _beginthread(ServerThreadInit, 0, NULL);
+#else
+       pthread_t      thread;
+       pthread_create(&thread, NULL, (void *(*)(void *))&ServerThreadInit, NULL);
+#endif
+}
+
+/***********************/
+/* Keyboard Definitons */
+/*        And          */
+/*     Functions       */
+/***********************/
+
+#define XK_space            0x020
+#define XK_asciitilde       0x07e
+
+#define XK_dead_grave       0xFE50
+#define XK_dead_acute       0xFE51
+#define XK_dead_circumflex  0xFE52
+#define XK_dead_tilde       0xFE53
+
+#define XK_BackSpace           0xFF08  
+#define XK_Tab                     0xFF09
+#define XK_Linefeed                0xFF0A
+#define XK_Clear                   0xFF0B
+#define XK_Return                  0xFF0D
+#define XK_Pause                   0xFF13      
+#define XK_Scroll_Lock         0xFF14
+#define XK_Sys_Req                 0xFF15
+#define XK_Escape                  0xFF1B
+
+#define XK_Delete                  0xFFFF
+
+#define XK_Home                        0xFF50
+#define XK_Left                        0xFF51  
+#define XK_Up                  0xFF52  
+#define XK_Right               0xFF53
+#define XK_Down                        0xFF54
+#define XK_Page_Up             0xFF55
+#define XK_Page_Down   0xFF56
+#define XK_End                 0xFF57  
+#define XK_Begin               0xFF58  
+
+#define XK_Select              0xFF60  
+#define XK_Print               0xFF61
+#define XK_Execute             0xFF62  
+#define XK_Insert              0xFF63  
+
+#define XK_Cancel              0xFF69  
+#define XK_Help                        0xFF6A
+#define XK_Break               0xFF6B
+#define XK_Num_Lock            0xFF7F
+
+#define XK_KP_Space            0xFF80
+#define XK_KP_Tab              0xFF89
+#define XK_KP_Enter            0xFF8D  
+
+#define XK_KP_Home             0xFF95
+#define XK_KP_Left             0xFF96
+#define XK_KP_Up               0xFF97
+#define XK_KP_Right            0xFF98
+#define XK_KP_Down             0xFF99
+#define XK_KP_Prior            0xFF9A
+#define XK_KP_Page_Up  0xFF9A
+#define XK_KP_Next             0xFF9B
+#define XK_KP_Page_Down        0xFF9B
+#define XK_KP_End              0xFF9C
+#define XK_KP_Begin            0xFF9D
+#define XK_KP_Insert   0xFF9E
+#define XK_KP_Delete   0xFF9F
+#define XK_KP_Equal            0xFFBD
+#define XK_KP_Multiply 0xFFAA
+#define XK_KP_Add              0xFFAB
+#define XK_KP_Separator        0xFFAC  
+#define XK_KP_Subtract 0xFFAD
+#define XK_KP_Decimal  0xFFAE
+#define XK_KP_Divide   0xFFAF
+
+#define XK_KP_F1               0xFF91
+#define XK_KP_F2               0xFF92
+#define XK_KP_F3               0xFF93
+#define XK_KP_F4               0xFF94
+
+#define XK_KP_0                        0xFFB0
+#define XK_KP_1                        0xFFB1
+#define XK_KP_2                        0xFFB2
+#define XK_KP_3                        0xFFB3
+#define XK_KP_4                        0xFFB4
+#define XK_KP_5                        0xFFB5
+#define XK_KP_6                        0xFFB6
+#define XK_KP_7                        0xFFB7
+#define XK_KP_8                        0xFFB8
+#define XK_KP_9                        0xFFB9
+
+#define XK_F1                  0xFFBE
+#define XK_F2                  0xFFBF
+#define XK_F3                  0xFFC0
+#define XK_F4                  0xFFC1
+#define XK_F5                  0xFFC2
+#define XK_F6                  0xFFC3
+#define XK_F7                  0xFFC4
+#define XK_F8                  0xFFC5
+#define XK_F9                  0xFFC6
+#define XK_F10                 0xFFC7
+#define XK_F11                 0xFFC8
+#define XK_F12                 0xFFC9
+#define XK_F13                 0xFFCA
+#define XK_F14                 0xFFCB
+#define XK_F15                 0xFFCC
+#define XK_F16                 0xFFCD
+#define XK_F17                 0xFFCE
+#define XK_F18                 0xFFCF
+#define XK_F19                 0xFFD0
+#define XK_F20                 0xFFD1
+#define XK_F21                 0xFFD2
+#define XK_F22                 0xFFD3
+#define XK_F23                 0xFFD4
+#define XK_F24                 0xFFD5
+
+
+#define XK_Shift_L             0xFFE1  
+#define XK_Shift_R             0xFFE2  
+#define XK_Control_L   0xFFE3  
+#define XK_Control_R   0xFFE4  
+#define XK_Caps_Lock   0xFFE5  
+#define XK_Shift_Lock  0xFFE6  
+#define XK_Meta_L              0xFFE7  
+#define XK_Meta_R              0xFFE8
+#define XK_Alt_L               0xFFE9
+#define XK_Alt_R               0xFFEA
+
+Bit32u rfb_ascii_to_key_event[0x5f] = {
+  //  !"#$%&'
+  BX_KEY_SPACE,
+  BX_KEY_1,
+  BX_KEY_SINGLE_QUOTE,
+  BX_KEY_3,
+  BX_KEY_4,
+  BX_KEY_5,
+  BX_KEY_7,
+  BX_KEY_SINGLE_QUOTE,
+
+  // ()*+,-./
+  BX_KEY_9,
+  BX_KEY_0,
+  BX_KEY_8,
+  BX_KEY_EQUALS,
+  BX_KEY_COMMA,
+  BX_KEY_MINUS,
+  BX_KEY_PERIOD,
+  BX_KEY_SLASH,
+
+  // 01234567
+  BX_KEY_0,
+  BX_KEY_1,
+  BX_KEY_2,
+  BX_KEY_3,
+  BX_KEY_4,
+  BX_KEY_5,
+  BX_KEY_6,
+  BX_KEY_7,
+
+  // 89:;<=>?
+  BX_KEY_8,
+  BX_KEY_9,
+  BX_KEY_SEMICOLON,
+  BX_KEY_SEMICOLON,
+  BX_KEY_COMMA,
+  BX_KEY_EQUALS,
+  BX_KEY_PERIOD,
+  BX_KEY_SLASH,
+
+  // @ABCDEFG
+  BX_KEY_2,
+  BX_KEY_A,
+  BX_KEY_B,
+  BX_KEY_C,
+  BX_KEY_D,
+  BX_KEY_E,
+  BX_KEY_F,
+  BX_KEY_G,
+
+
+  // HIJKLMNO
+  BX_KEY_H,
+  BX_KEY_I,
+  BX_KEY_J,
+  BX_KEY_K,
+  BX_KEY_L,
+  BX_KEY_M,
+  BX_KEY_N,
+  BX_KEY_O,
+
+
+  // PQRSTUVW
+  BX_KEY_P,
+  BX_KEY_Q,
+  BX_KEY_R,
+  BX_KEY_S,
+  BX_KEY_T,
+  BX_KEY_U,
+  BX_KEY_V,
+  BX_KEY_W,
+
+  // XYZ[\]^_
+  BX_KEY_X,
+  BX_KEY_Y,
+  BX_KEY_Z,
+  BX_KEY_LEFT_BRACKET,
+  BX_KEY_BACKSLASH,
+  BX_KEY_RIGHT_BRACKET,
+  BX_KEY_6,
+  BX_KEY_MINUS,
+
+  // `abcdefg
+  BX_KEY_GRAVE,
+  BX_KEY_A,
+  BX_KEY_B,
+  BX_KEY_C,
+  BX_KEY_D,
+  BX_KEY_E,
+  BX_KEY_F,
+  BX_KEY_G,
+
+  // hijklmno
+  BX_KEY_H,
+  BX_KEY_I,
+  BX_KEY_J,
+  BX_KEY_K,
+  BX_KEY_L,
+  BX_KEY_M,
+  BX_KEY_N,
+  BX_KEY_O,
+
+  // pqrstuvw
+  BX_KEY_P,
+  BX_KEY_Q,
+  BX_KEY_R,
+  BX_KEY_S,
+  BX_KEY_T,
+  BX_KEY_U,
+  BX_KEY_V,
+  BX_KEY_W,
+
+  // xyz{|}~
+  BX_KEY_X,
+  BX_KEY_Y,
+  BX_KEY_Z,
+  BX_KEY_LEFT_BRACKET,
+  BX_KEY_BACKSLASH,
+  BX_KEY_RIGHT_BRACKET,
+  BX_KEY_GRAVE
+  };
+
+void rfbKeyPressed(Bit32u key, int press_release)
+{
+  Bit32u key_event;
+
+  if((key >= XK_space) && (key <= XK_asciitilde)) {
+    key_event = rfb_ascii_to_key_event[key - XK_space];
+  } else {
+    switch (key) {
+      case XK_KP_1:
+#ifdef XK_KP_End
+      case XK_KP_End:
+#endif
+        key_event = BX_KEY_KP_END; break;
+
+      case XK_KP_2:
+#ifdef XK_KP_Down
+      case XK_KP_Down:
+#endif
+        key_event = BX_KEY_KP_DOWN; break;
+
+      case XK_KP_3:
+#ifdef XK_KP_Page_Down
+      case XK_KP_Page_Down:
+#endif
+        key_event = BX_KEY_KP_PAGE_DOWN; break;
+
+      case XK_KP_4:
+#ifdef XK_KP_Left
+      case XK_KP_Left:
+#endif
+        key_event = BX_KEY_KP_LEFT; break;
+
+      case XK_KP_5:
+#ifdef XK_KP_Begin
+      case XK_KP_Begin:
+#endif
+        key_event = BX_KEY_KP_5; break;
+
+      case XK_KP_6:
+#ifdef XK_KP_Right
+      case XK_KP_Right:
+#endif
+        key_event = BX_KEY_KP_RIGHT; break;
+
+      case XK_KP_7:
+#ifdef XK_KP_Home
+      case XK_KP_Home:
+#endif
+        key_event = BX_KEY_KP_HOME; break;
+
+      case XK_KP_8:
+#ifdef XK_KP_Up
+      case XK_KP_Up:
+#endif
+        key_event = BX_KEY_KP_UP; break;
+
+      case XK_KP_9:
+#ifdef XK_KP_Page_Up
+      case XK_KP_Page_Up:
+#endif
+        key_event = BX_KEY_KP_PAGE_UP; break;
+
+      case XK_KP_0:
+#ifdef XK_KP_Insert
+      case XK_KP_Insert:
+#endif
+        key_event = BX_KEY_KP_INSERT; break;
+
+      case XK_KP_Decimal:
+#ifdef XK_KP_Delete
+      case XK_KP_Delete:
+#endif
+        key_event = BX_KEY_KP_DELETE; break;
+
+#ifdef XK_KP_Enter
+      case XK_KP_Enter:    key_event = BX_KEY_KP_ENTER; break;
+#endif
+
+      case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
+      case XK_KP_Add:      key_event = BX_KEY_KP_ADD; break;
+
+      case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
+      case XK_KP_Divide:   key_event = BX_KEY_KP_DIVIDE; break;
+
+
+      case XK_Up:          key_event = BX_KEY_UP; break;
+      case XK_Down:        key_event = BX_KEY_DOWN; break;
+      case XK_Left:        key_event = BX_KEY_LEFT; break;
+      case XK_Right:       key_event = BX_KEY_RIGHT; break;
+
+
+      case XK_Delete:      key_event = BX_KEY_DELETE; break;
+      case XK_BackSpace:   key_event = BX_KEY_BACKSPACE; break;
+      case XK_Tab:         key_event = BX_KEY_TAB; break;
+#ifdef XK_ISO_Left_Tab
+      case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
+#endif
+      case XK_Return:      key_event = BX_KEY_ENTER; break;
+      case XK_Escape:      key_event = BX_KEY_ESC; break;
+      case XK_F1:          key_event = BX_KEY_F1; break;
+      case XK_F2:          key_event = BX_KEY_F2; break;
+      case XK_F3:          key_event = BX_KEY_F3; break;
+      case XK_F4:          key_event = BX_KEY_F4; break;
+      case XK_F5:          key_event = BX_KEY_F5; break;
+      case XK_F6:          key_event = BX_KEY_F6; break;
+      case XK_F7:          key_event = BX_KEY_F7; break;
+      case XK_F8:          key_event = BX_KEY_F8; break;
+      case XK_F9:          key_event = BX_KEY_F9; break;
+      case XK_F10:         key_event = BX_KEY_F10; break;
+      case XK_F11:         key_event = BX_KEY_F11; break;
+      case XK_F12:         key_event = BX_KEY_F12; break;
+      case XK_Control_L:   key_event = BX_KEY_CTRL_L; break;
+#ifdef XK_Control_R
+      case XK_Control_R:   key_event = BX_KEY_CTRL_R; break;
+#endif
+      case XK_Shift_L:     key_event = BX_KEY_SHIFT_L; break;
+      case XK_Shift_R:     key_event = BX_KEY_SHIFT_R; break;
+      case XK_Alt_L:       key_event = BX_KEY_ALT_L; break;
+#ifdef XK_Alt_R
+      case XK_Alt_R:       key_event = BX_KEY_ALT_R; break;
+#endif
+      case XK_Caps_Lock:   key_event = BX_KEY_CAPS_LOCK; break;
+      case XK_Num_Lock:    key_event = BX_KEY_NUM_LOCK; break;
+#ifdef XK_Scroll_Lock
+      case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
+#endif
+#ifdef XK_Print
+      case XK_Print:       key_event = BX_KEY_PRINT; break;
+#endif
+#ifdef XK_Pause
+      case XK_Pause:       key_event = BX_KEY_PAUSE; break;
+#endif
+
+      case XK_Insert:      key_event = BX_KEY_INSERT; break;
+      case XK_Home:        key_event = BX_KEY_HOME; break;
+      case XK_End:         key_event = BX_KEY_END; break;
+      case XK_Page_Up:     key_event = BX_KEY_PAGE_UP; break;
+      case XK_Page_Down:   key_event = BX_KEY_PAGE_DOWN; break;
+
+      default:
+        BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key));
+        fprintf(stderr, "RFB: rfbKeyPress(): key %04x unhandled!\n", key);
+        return;
+        break;
+    }
+  }
+
+  if (press_release) key_event |= BX_KEY_RELEASED;
+  DEV_kbd_gen_scancode(key_event);
+}
+
+void rfbMouseMove(int x, int y, int bmask)
+{
+  static int oldx = -1;
+  static int oldy = -1;
+  int xorigin;
+
+  if (oldx == oldy == -1) {
+    oldx = x;
+    oldy = y;
+    return;
+  }
+  if(y > rfbHeaderbarY) {
+    //DEV_mouse_motion(x, y - rfbHeaderbarY, buttons);
+    DEV_mouse_motion(x - oldx, oldy - y, bmask);
+    oldx = x;
+    oldy = y;
+  } else {
+    if (bmask == 1) {
+      for (unsigned i=0; i<rfbHeaderbarBitmapCount; i++) {
+        if (rfbHeaderbarBitmaps[i].alignment == BX_GRAVITY_LEFT)
+          xorigin = rfbHeaderbarBitmaps[i].xorigin;
+        else
+          xorigin = rfbDimensionX - rfbHeaderbarBitmaps[i].xorigin;
+        if ( (x>=xorigin) && (x<(xorigin+int(rfbBitmaps[rfbHeaderbarBitmaps[i].index].xdim))) ) {
+          rfbHeaderbarBitmaps[i].f();
+          return;
+        }
+      }
+    }
+  }
+}
+
+  void
+bx_rfb_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+
+#endif /* if BX_WITH_RFB */
diff --git a/tools/ioemu/gui/rfb.h b/tools/ioemu/gui/rfb.h
new file mode 100644 (file)
index 0000000..948ac82
--- /dev/null
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfb.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// rfb.h
+// This includes the rfb spec header, the port numbers,
+// the CARD type definitions and various useful macros.
+//
+
+#ifndef RFB_H__
+#define RFB_H__
+
+// Define the CARD* types as used in X11/Xmd.h
+
+typedef unsigned long CARD32;
+typedef unsigned short CARD16;
+typedef short INT16;
+typedef unsigned char  CARD8;
+
+// Define the port number offsets
+#define FLASH_PORT_OFFSET 5400
+#define INCOMING_PORT_OFFSET 5500
+#define HTTP_PORT_OFFSET 5800  // we don't use this in Venice
+#define RFB_PORT_OFFSET 5900
+
+#define _SIZEOF(x) sz_##x
+#define SIZEOF(x) _SIZEOF(x)
+
+#define PORT_TO_DISPLAY(p) ( (p) - RFB_PORT_OFFSET )
+#define DISPLAY_TO_PORT(d) ( (d) + RFB_PORT_OFFSET )
+
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ETIMEDOUT WSAETIMEDOUT
+
+#endif
diff --git a/tools/ioemu/gui/rfbproto.h b/tools/ioemu/gui/rfbproto.h
new file mode 100644 (file)
index 0000000..a2be5f8
--- /dev/null
@@ -0,0 +1,675 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: rfbproto.h,v 1.2 2001/10/03 13:10:37 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ *  Copyright (C) 1997, 1998 Olivetti & Oracle Research Laboratory
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+/*
+ * rfbproto.h - header file for the RFB protocol version 3.3
+ *
+ * Uses types CARD<n> for an n-bit unsigned integer, INT<n> for an n-bit signed
+ * integer (for n = 8, 16 and 32).
+ *
+ * All multiple byte integers are in big endian (network) order (most
+ * significant byte first).  Unless noted otherwise there is no special
+ * alignment of protocol structures.
+ *
+ *
+ * Once the initial handshaking is done, all messages start with a type byte,
+ * (usually) followed by message-specific data.  The order of definitions in
+ * this file is as follows:
+ *
+ *  (1) Structures used in several types of message.
+ *  (2) Structures used in the initial handshaking.
+ *  (3) Message types.
+ *  (4) Encoding types.
+ *  (5) For each message type, the form of the data following the type byte.
+ *      Sometimes this is defined by a single structure but the more complex
+ *      messages have to be explained by comments.
+ */
+
+
+/*****************************************************************************
+ *
+ * Structures used in several messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify a rectangle.  This structure is a multiple of 4
+ * bytes so that it can be interspersed with 32-bit pixel data without
+ * affecting alignment.
+ */
+
+typedef struct {
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbRectangle;
+
+#define sz_rfbRectangle 8
+
+
+/*-----------------------------------------------------------------------------
+ * Structure used to specify pixel format.
+ */
+
+typedef struct {
+
+    CARD8 bitsPerPixel;                /* 8,16,32 only */
+
+    CARD8 depth;               /* 8 to 32 */
+
+    CARD8 bigEndian;           /* True if multi-byte pixels are interpreted
+                                  as big endian, or if single-bit-per-pixel
+                                  has most significant bit of the byte
+                                  corresponding to first (leftmost) pixel. Of
+                                  course this is meaningless for 8 bits/pix */
+
+    CARD8 trueColour;          /* If false then we need a "colour map" to
+                                  convert pixels to RGB.  If true, xxxMax and
+                                  xxxShift specify bits used for red, green
+                                  and blue */
+
+    /* the following fields are only meaningful if trueColour is true */
+
+    CARD16 redMax;             /* maximum red value (= 2^n - 1 where n is the
+                                  number of bits used for red). Note this
+                                  value is always in big endian order. */
+
+    CARD16 greenMax;           /* similar for green */
+
+    CARD16 blueMax;            /* and blue */
+
+    CARD8 redShift;            /* number of shifts needed to get the red
+                                  value in a pixel to the least significant
+                                  bit. To find the red value from a given
+                                  pixel, do the following:
+                                  1) Swap pixel value according to bigEndian
+                                     (e.g. if bigEndian is false and host byte
+                                     order is big endian, then swap).
+                                  2) Shift right by redShift.
+                                  3) AND with redMax (in host byte order).
+                                  4) You now have the red value between 0 and
+                                     redMax. */
+
+    CARD8 greenShift;          /* similar for green */
+
+    CARD8 blueShift;           /* and blue */
+
+    CARD8 pad1;
+    CARD16 pad2;
+
+} rfbPixelFormat;
+
+#define sz_rfbPixelFormat 16
+
+
+
+/*****************************************************************************
+ *
+ * Initial handshaking messages
+ *
+ *****************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * Protocol Version
+ *
+ * The server always sends 12 bytes to start which identifies the latest RFB
+ * protocol version number which it supports.  These bytes are interpreted
+ * as a string of 12 ASCII characters in the format "RFB xxx.yyy\n" where
+ * xxx and yyy are the major and minor version numbers (for version 3.3
+ * this is "RFB 003.003\n").
+ *
+ * The client then replies with a similar 12-byte message giving the version
+ * number of the protocol which should actually be used (which may be different
+ * to that quoted by the server).
+ *
+ * It is intended that both clients and servers may provide some level of
+ * backwards compatibility by this mechanism.  Servers in particular should
+ * attempt to provide backwards compatibility, and even forwards compatibility
+ * to some extent.  For example if a client demands version 3.1 of the
+ * protocol, a 3.0 server can probably assume that by ignoring requests for
+ * encoding types it doesn't understand, everything will still work OK.  This
+ * will probably not be the case for changes in the major version number.
+ *
+ * The format string below can be used in sprintf or sscanf to generate or
+ * decode the version string respectively.
+ */
+
+#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
+#define rfbProtocolMajorVersion 3
+#define rfbProtocolMinorVersion 3
+
+typedef char rfbProtocolVersionMsg[13];        /* allow extra byte for null */
+
+#define sz_rfbProtocolVersionMsg 12
+
+
+/*-----------------------------------------------------------------------------
+ * Authentication
+ *
+ * Once the protocol version has been decided, the server then sends a 32-bit
+ * word indicating whether any authentication is needed on the connection.
+ * The value of this word determines the authentication scheme in use.  For
+ * version 3.0 of the protocol this may have one of the following values:
+ */
+
+#define rfbConnFailed 0
+#define rfbNoAuth 1
+#define rfbVncAuth 2
+
+/*
+ * rfbConnFailed:      For some reason the connection failed (e.g. the server
+ *                     cannot support the desired protocol version).  This is
+ *                     followed by a string describing the reason (where a
+ *                     string is specified as a 32-bit length followed by that
+ *                     many ASCII characters).
+ *
+ * rfbNoAuth:          No authentication is needed.
+ *
+ * rfbVncAuth:         The VNC authentication scheme is to be used.  A 16-byte
+ *                     challenge follows, which the client encrypts as
+ *                     appropriate using the password and sends the resulting
+ *                     16-byte response.  If the response is correct, the
+ *                     server sends the 32-bit word rfbVncAuthOK.  If a simple
+ *                     failure happens, the server sends rfbVncAuthFailed and
+ *                     closes the connection. If the server decides that too
+ *                     many failures have occurred, it sends rfbVncAuthTooMany
+ *                     and closes the connection.  In the latter case, the
+ *                     server should not allow an immediate reconnection by
+ *                     the client.
+ */
+
+#define rfbVncAuthOK 0
+#define rfbVncAuthFailed 1
+#define rfbVncAuthTooMany 2
+
+
+/*-----------------------------------------------------------------------------
+ * Client Initialisation Message
+ *
+ * Once the client and server are sure that they're happy to talk to one
+ * another, the client sends an initialisation message.  At present this
+ * message only consists of a boolean indicating whether the server should try
+ * to share the desktop by leaving other clients connected, or give exclusive
+ * access to this client by disconnecting all other clients.
+ */
+
+typedef struct {
+    CARD8 shared;
+} rfbClientInitMsg;
+
+#define sz_rfbClientInitMsg 1
+
+
+/*-----------------------------------------------------------------------------
+ * Server Initialisation Message
+ *
+ * After the client initialisation message, the server sends one of its own.
+ * This tells the client the width and height of the server's framebuffer,
+ * its pixel format and the name associated with the desktop.
+ */
+
+typedef struct {
+    CARD16 framebufferWidth;
+    CARD16 framebufferHeight;
+    rfbPixelFormat format;     /* the server's preferred pixel format */
+    CARD32 nameLength;
+    /* followed by char name[nameLength] */
+} rfbServerInitMsg;
+
+#define sz_rfbServerInitMsg (8 + sz_rfbPixelFormat)
+
+
+/*
+ * Following the server initialisation message it's up to the client to send
+ * whichever protocol messages it wants.  Typically it will send a
+ * SetPixelFormat message and a SetEncodings message, followed by a
+ * FramebufferUpdateRequest.  From then on the server will send
+ * FramebufferUpdate messages in response to the client's
+ * FramebufferUpdateRequest messages.  The client should send
+ * FramebufferUpdateRequest messages with incremental set to true when it has
+ * finished processing one FramebufferUpdate and is ready to process another.
+ * With a fast client, the rate at which FramebufferUpdateRequests are sent
+ * should be regulated to avoid hogging the network.
+ */
+
+
+
+/*****************************************************************************
+ *
+ * Message types
+ *
+ *****************************************************************************/
+
+/* server -> client */
+
+#define rfbFramebufferUpdate 0
+#define rfbSetColourMapEntries 1
+#define rfbBell 2
+#define rfbServerCutText 3
+
+
+/* client -> server */
+
+#define rfbSetPixelFormat 0
+#define rfbFixColourMapEntries 1       /* not currently supported */
+#define rfbSetEncodings 2
+#define rfbFramebufferUpdateRequest 3
+#define rfbKeyEvent 4
+#define rfbPointerEvent 5
+#define rfbClientCutText 6
+
+
+
+
+/*****************************************************************************
+ *
+ * Encoding types
+ *
+ *****************************************************************************/
+
+#define rfbEncodingRaw 0
+#define rfbEncodingCopyRect 1
+#define rfbEncodingRRE 2
+#define rfbEncodingCoRRE 4
+#define rfbEncodingHextile 5
+
+
+
+/*****************************************************************************
+ *
+ * Server -> client message definitions
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdate - a block of rectangles to be copied to the framebuffer.
+ *
+ * This message consists of a header giving the number of rectangles of pixel
+ * data followed by the rectangles themselves.  The header is padded so that
+ * together with the type byte it is an exact multiple of 4 bytes (to help
+ * with alignment of 32-bit pixels):
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFramebufferUpdate */
+    CARD8 pad;
+    CARD16 nRects;
+    /* followed by nRects rectangles */
+} rfbFramebufferUpdateMsg;
+
+#define sz_rfbFramebufferUpdateMsg 4
+
+/*
+ * Each rectangle of pixel data consists of a header describing the position
+ * and size of the rectangle and a type word describing the encoding of the
+ * pixel data, followed finally by the pixel data.  Note that if the client has
+ * not sent a SetEncodings message then it will only receive raw pixel data.
+ * Also note again that this structure is a multiple of 4 bytes.
+ */
+
+typedef struct {
+    rfbRectangle r;
+    CARD32 encoding;   /* one of the encoding types rfbEncoding... */
+} rfbFramebufferUpdateRectHeader;
+
+#define sz_rfbFramebufferUpdateRectHeader (sz_rfbRectangle + 4)
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Raw Encoding.  Pixels are sent in top-to-bottom scanline order,
+ * left-to-right within a scanline with no padding in between.
+ */
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CopyRect Encoding.  The pixels are specified simply by the x and y position
+ * of the source rectangle.
+ */
+
+typedef struct {
+    CARD16 srcX;
+    CARD16 srcY;
+} rfbCopyRect;
+
+#define sz_rfbCopyRect 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * RRE - Rise-and-Run-length Encoding.  We have an rfbRREHeader structure
+ * giving the number of subrectangles following.  Finally the data follows in
+ * the form [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbRectangle>].
+ */
+
+typedef struct {
+    CARD32 nSubrects;
+} rfbRREHeader;
+
+#define sz_rfbRREHeader 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * CoRRE - Compact RRE Encoding.  We have an rfbRREHeader structure giving
+ * the number of subrectangles following.  Finally the data follows in the form
+ * [<bgpixel><subrect><subrect>...] where each <subrect> is
+ * [<pixel><rfbCoRRERectangle>].  This means that
+ * the whole rectangle must be at most 255x255 pixels.
+ */
+
+typedef struct {
+    CARD8 x;
+    CARD8 y;
+    CARD8 w;
+    CARD8 h;
+} rfbCoRRERectangle;
+
+#define sz_rfbCoRRERectangle 4
+
+
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * Hextile Encoding.  The rectangle is divided up into "tiles" of 16x16 pixels,
+ * starting at the top left going in left-to-right, top-to-bottom order.  If
+ * the width of the rectangle is not an exact multiple of 16 then the width of
+ * the last tile in each row will be correspondingly smaller.  Similarly if the
+ * height is not an exact multiple of 16 then the height of each tile in the
+ * final row will also be smaller.  Each tile begins with a "subencoding" type
+ * byte, which is a mask made up of a number of bits.  If the Raw bit is set
+ * then the other bits are irrelevant; w*h pixel values follow (where w and h
+ * are the width and height of the tile).  Otherwise the tile is encoded in a
+ * similar way to RRE, except that the position and size of each subrectangle
+ * can be specified in just two bytes.  The other bits in the mask are as
+ * follows:
+ *
+ * BackgroundSpecified - if set, a pixel value follows which specifies
+ *    the background colour for this tile.  The first non-raw tile in a
+ *    rectangle must have this bit set.  If this bit isn't set then the
+ *    background is the same as the last tile.
+ *
+ * ForegroundSpecified - if set, a pixel value follows which specifies
+ *    the foreground colour to be used for all subrectangles in this tile.
+ *    If this bit is set then the SubrectsColoured bit must be zero.
+ *
+ * AnySubrects - if set, a single byte follows giving the number of
+ *    subrectangles following.  If not set, there are no subrectangles (i.e.
+ *    the whole tile is just solid background colour).
+ *
+ * SubrectsColoured - if set then each subrectangle is preceded by a pixel
+ *    value giving the colour of that subrectangle.  If not set, all
+ *    subrectangles are the same colour, the foreground colour;  if the
+ *    ForegroundSpecified bit wasn't set then the foreground is the same as
+ *    the last tile.
+ *
+ * The position and size of each subrectangle is specified in two bytes.  The
+ * Pack macros below can be used to generate the two bytes from x, y, w, h,
+ * and the Extract macros can be used to extract the x, y, w, h values from
+ * the two bytes.
+ */
+
+#define rfbHextileRaw                  (1 << 0)
+#define rfbHextileBackgroundSpecified  (1 << 1)
+#define rfbHextileForegroundSpecified  (1 << 2)
+#define rfbHextileAnySubrects          (1 << 3)
+#define rfbHextileSubrectsColoured     (1 << 4)
+
+#define rfbHextilePackXY(x,y) (((x) << 4) | (y))
+#define rfbHextilePackWH(w,h) ((((w)-1) << 4) | ((h)-1))
+#define rfbHextileExtractX(byte) ((byte) >> 4)
+#define rfbHextileExtractY(byte) ((byte) & 0xf)
+#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
+#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
+
+
+/*-----------------------------------------------------------------------------
+ * SetColourMapEntries - these messages are only sent if the pixel
+ * format uses a "colour map" (i.e. trueColour false) and the client has not
+ * fixed the entire colour map using FixColourMapEntries.  In addition they
+ * will only start being sent after the client has sent its first
+ * FramebufferUpdateRequest.  So if the client always tells the server to use
+ * trueColour then it never needs to process this type of message.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbSetColourMapEntriesMsg;
+
+#define sz_rfbSetColourMapEntriesMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * Bell - ring a bell on the client if it has one.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbBell */
+} rfbBellMsg;
+
+#define sz_rfbBellMsg 1
+
+
+
+/*-----------------------------------------------------------------------------
+ * ServerCutText - the server has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbServerCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbServerCutTextMsg;
+
+#define sz_rfbServerCutTextMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all server->client messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbFramebufferUpdateMsg fu;
+    rfbSetColourMapEntriesMsg scme;
+    rfbBellMsg b;
+    rfbServerCutTextMsg sct;
+} rfbServerToClientMsg;
+
+
+
+/*****************************************************************************
+ *
+ * Message definitions (client -> server)
+ *
+ *****************************************************************************/
+
+
+/*-----------------------------------------------------------------------------
+ * SetPixelFormat - tell the RFB server the format in which the client wants
+ * pixels sent.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetPixelFormat */
+    CARD8 pad1;
+    CARD16 pad2;
+    rfbPixelFormat format;
+} rfbSetPixelFormatMsg;
+
+#define sz_rfbSetPixelFormatMsg (sz_rfbPixelFormat + 4)
+
+
+/*-----------------------------------------------------------------------------
+ * FixColourMapEntries - when the pixel format uses a "colour map", fix
+ * read-only colour map entries.
+ *
+ *    ***************** NOT CURRENTLY SUPPORTED *****************
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFixColourMapEntries */
+    CARD8 pad;
+    CARD16 firstColour;
+    CARD16 nColours;
+
+    /* Followed by nColours * 3 * CARD16
+       r1, g1, b1, r2, g2, b2, r3, g3, b3, ..., rn, bn, gn */
+
+} rfbFixColourMapEntriesMsg;
+
+#define sz_rfbFixColourMapEntriesMsg 6
+
+
+/*-----------------------------------------------------------------------------
+ * SetEncodings - tell the RFB server which encoding types we accept.  Put them
+ * in order of preference, if we have any.  We may always receive raw
+ * encoding, even if we don't specify it here.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbSetEncodings */
+    CARD8 pad;
+    CARD16 nEncodings;
+    /* followed by nEncodings * CARD32 encoding types */
+} rfbSetEncodingsMsg;
+
+#define sz_rfbSetEncodingsMsg 4
+
+
+/*-----------------------------------------------------------------------------
+ * FramebufferUpdateRequest - request for a framebuffer update.  If incremental
+ * is true then the client just wants the changes since the last update.  If
+ * false then it wants the whole of the specified rectangle.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbFramebufferUpdateRequest */
+    CARD8 incremental;
+    CARD16 x;
+    CARD16 y;
+    CARD16 w;
+    CARD16 h;
+} rfbFramebufferUpdateRequestMsg;
+
+#define sz_rfbFramebufferUpdateRequestMsg 10
+
+
+/*-----------------------------------------------------------------------------
+ * KeyEvent - key press or release
+ *
+ * Keys are specified using the "keysym" values defined by the X Window System.
+ * For most ordinary keys, the keysym is the same as the corresponding ASCII
+ * value.  Other common keys are:
+ *
+ * BackSpace           0xff08
+ * Tab                 0xff09
+ * Return or Enter     0xff0d
+ * Escape              0xff1b
+ * Insert              0xff63
+ * Delete              0xffff
+ * Home                        0xff50
+ * End                 0xff57
+ * Page Up             0xff55
+ * Page Down           0xff56
+ * Left                        0xff51
+ * Up                  0xff52
+ * Right               0xff53
+ * Down                        0xff54
+ * F1                  0xffbe
+ * F2                  0xffbf
+ * ...                 ...
+ * F12                 0xffc9
+ * Shift               0xffe1
+ * Control             0xffe3
+ * Meta                        0xffe7
+ * Alt                 0xffe9
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbKeyEvent */
+    CARD8 down;                        /* true if down (press), false if up */
+    CARD16 pad;
+    CARD32 key;                        /* key is specified as an X keysym */
+} rfbKeyEventMsg;
+
+#define sz_rfbKeyEventMsg 8
+
+
+/*-----------------------------------------------------------------------------
+ * PointerEvent - mouse/pen move and/or button press.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbPointerEvent */
+    CARD8 buttonMask;          /* bits 0-7 are buttons 1-8, 0=up, 1=down */
+    CARD16 x;
+    CARD16 y;
+} rfbPointerEventMsg;
+
+#define rfbButton1Mask 1
+#define rfbButton2Mask 2
+#define rfbButton3Mask 4
+
+#define sz_rfbPointerEventMsg 6
+
+
+
+/*-----------------------------------------------------------------------------
+ * ClientCutText - the client has new text in its cut buffer.
+ */
+
+typedef struct {
+    CARD8 type;                        /* always rfbClientCutText */
+    CARD8 pad1;
+    CARD16 pad2;
+    CARD32 length;
+    /* followed by char text[length] */
+} rfbClientCutTextMsg;
+
+#define sz_rfbClientCutTextMsg 8
+
+
+
+/*-----------------------------------------------------------------------------
+ * Union of all client->server messages.
+ */
+
+typedef union {
+    CARD8 type;
+    rfbSetPixelFormatMsg spf;
+    rfbFixColourMapEntriesMsg fcme;
+    rfbSetEncodingsMsg se;
+    rfbFramebufferUpdateRequestMsg fur;
+    rfbKeyEventMsg ke;
+    rfbPointerEventMsg pe;
+    rfbClientCutTextMsg cct;
+} rfbClientToServerMsg;
diff --git a/tools/ioemu/gui/sdl.h b/tools/ioemu/gui/sdl.h
new file mode 100644 (file)
index 0000000..c8df029
--- /dev/null
@@ -0,0 +1,1038 @@
+#define BX_HEADERBAR_FG_RED    0x10
+#define BX_HEADERBAR_FG_GREEN  0x10
+#define BX_HEADERBAR_FG_BLUE   0x10
+#define BX_HEADERBAR_BG_RED    0xD0
+#define BX_HEADERBAR_BG_GREEN  0xD0
+#define BX_HEADERBAR_BG_BLUE   0xD0
+
+unsigned char sdl_font8x16[256][16] = {
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 0
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0, 126, 129, 165, 129, 129, 189,    // 1
+    153, 129, 129, 126,   0,   0,   0,   0 },
+  {   0,   0, 126, 255, 219, 255, 255, 195,    // 2
+    231, 255, 255, 126,   0,   0,   0,   0 },
+  {   0,   0,   0,   0, 108, 254, 254, 254,    // 3
+    254, 124,  56,  16,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  16,  56, 124, 254,    // 4
+    124,  56,  16,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,  24,  60,  60, 231, 231,    // 5
+    231,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0,   0,  24,  60, 126, 255, 255,    // 6
+    126,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,  24,  60,    // 7
+     60,  24,   0,   0,   0,   0,   0,   0 },
+  { 255, 255, 255, 255, 255, 255, 231, 195,    // 8
+    195, 231, 255, 255, 255, 255, 255, 255 },
+  {   0,   0,   0,   0,   0,  60, 102,  66,    // 9
+     66, 102,  60,   0,   0,   0,   0,   0 },
+  { 255, 255, 255, 255, 255, 195, 153, 189,    // 10
+    189, 153, 195, 255, 255, 255, 255, 255 },
+  {   0,   0,  30,  14,  26,  50, 120, 204,    // 11
+    204, 204, 204, 120,   0,   0,   0,   0 },
+  {   0,   0,  60, 102, 102, 102, 102,  60,    // 12
+     24, 126,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,  63,  51,  63,  48,  48,  48,    // 13
+     48, 112, 240, 224,   0,   0,   0,   0 },
+  {   0,   0, 127,  99, 127,  99,  99,  99,    // 14
+     99, 103, 231, 230, 192,   0,   0,   0 },
+  {   0,   0,   0,  24,  24, 219,  60, 231,    // 15
+     60, 219,  24,  24,   0,   0,   0,   0 },
+  {   0, 128, 192, 224, 240, 248, 254, 248,    // 16
+    240, 224, 192, 128,   0,   0,   0,   0 },
+  {   0,   2,   6,  14,  30,  62, 254,  62,    // 17
+     30,  14,   6,   2,   0,   0,   0,   0 },
+  {   0,   0,  24,  60, 126,  24,  24,  24,    // 18
+    126,  60,  24,   0,   0,   0,   0,   0 },
+  {   0,   0, 102, 102, 102, 102, 102, 102,    // 19
+    102,   0, 102, 102,   0,   0,   0,   0 },
+  {   0,   0, 127, 219, 219, 219, 123,  27,    // 20
+     27,  27,  27,  27,   0,   0,   0,   0 },
+  {   0, 124, 198,  96,  56, 108, 198, 198,    // 21
+    108,  56,  12, 198, 124,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 22
+    254, 254, 254, 254,   0,   0,   0,   0 },
+  {   0,   0,  24,  60, 126,  24,  24,  24,    // 23
+    126,  60,  24, 126,   0,   0,   0,   0 },
+  {   0,   0,  24,  60, 126,  24,  24,  24,    // 24
+     24,  24,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,  24,  24,  24,  24,  24,  24,    // 25
+     24, 126,  60,  24,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  24,  12, 254,    // 26
+     12,  24,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  48,  96, 254,    // 27
+     96,  48,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0, 192, 192,    // 28
+    192, 254,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  40, 108, 254,    // 29
+    108,  40,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  16,  56,  56, 124,    // 30
+    124, 254, 254,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0, 254, 254, 124, 124,    // 31
+     56,  56,  16,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 32
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,  24,  60,  60,  60,  24,  24,    // 33
+     24,   0,  24,  24,   0,   0,   0,   0 },
+  {   0, 102, 102, 102,  36,   0,   0,   0,    // 34
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0, 108, 108, 254, 108, 108,    // 35
+    108, 254, 108, 108,   0,   0,   0,   0 },
+  {  24,  24, 124, 198, 194, 192, 124,   6,    // 36
+      6, 134, 198, 124,  24,  24,   0,   0 },
+  {   0,   0,   0,   0, 194, 198,  12,  24,    // 37
+     48,  96, 198, 134,   0,   0,   0,   0 },
+  {   0,   0,  56, 108, 108,  56, 118, 220,    // 38
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  48,  48,  48,  96,   0,   0,   0,    // 39
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,  12,  24,  48,  48,  48,  48,    // 40
+     48,  48,  24,  12,   0,   0,   0,   0 },
+  {   0,   0,  48,  24,  12,  12,  12,  12,    // 41
+     12,  12,  24,  48,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 102,  60, 255,    // 42
+     60, 102,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  24,  24, 126,    // 43
+     24,  24,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 44
+      0,  24,  24,  24,  48,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0, 254,    // 45
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 46
+      0,   0,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   2,   6,  12,  24,    // 47
+     48,  96, 192, 128,   0,   0,   0,   0 },
+  {   0,   0,  56, 108, 198, 198, 214, 214,    // 48
+    198, 198, 108,  56,   0,   0,   0,   0 },
+  {   0,   0,  24,  56, 120,  24,  24,  24,    // 49
+     24,  24,  24, 126,   0,   0,   0,   0 },
+  {   0,   0, 124, 198,   6,  12,  24,  48,    // 50
+     96, 192, 198, 254,   0,   0,   0,   0 },
+  {   0,   0, 124, 198,   6,   6,  60,   6,    // 51
+      6,   6, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,  12,  28,  60, 108, 204, 254,    // 52
+     12,  12,  12,  30,   0,   0,   0,   0 },
+  {   0,   0, 254, 192, 192, 192, 252,   6,    // 53
+      6,   6, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,  56,  96, 192, 192, 252, 198,    // 54
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 254, 198,   6,   6,  12,  24,    // 55
+     48,  48,  48,  48,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198, 198, 124, 198,    // 56
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198, 198, 126,   6,    // 57
+      6,   6,  12, 120,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  24,  24,   0,   0,    // 58
+      0,  24,  24,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  24,  24,   0,   0,    // 59
+      0,  24,  24,  48,   0,   0,   0,   0 },
+  {   0,   0,   0,   6,  12,  24,  48,  96,    // 60
+     48,  24,  12,   6,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 126,   0,   0,    // 61
+    126,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,  96,  48,  24,  12,   6,    // 62
+     12,  24,  48,  96,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198,  12,  24,  24,    // 63
+     24,   0,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,   0, 124, 198, 198, 222, 222,    // 64
+    222, 220, 192, 124,   0,   0,   0,   0 },
+  {   0,   0,  16,  56, 108, 198, 198, 254,    // 65
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0, 252, 102, 102, 102, 124, 102,    // 66
+    102, 102, 102, 252,   0,   0,   0,   0 },
+  {   0,   0,  60, 102, 194, 192, 192, 192,    // 67
+    192, 194, 102,  60,   0,   0,   0,   0 },
+  {   0,   0, 248, 108, 102, 102, 102, 102,    // 68
+    102, 102, 108, 248,   0,   0,   0,   0 },
+  {   0,   0, 254, 102,  98, 104, 120, 104,    // 69
+     96,  98, 102, 254,   0,   0,   0,   0 },
+  {   0,   0, 254, 102,  98, 104, 120, 104,    // 70
+     96,  96,  96, 240,   0,   0,   0,   0 },
+  {   0,   0,  60, 102, 194, 192, 192, 222,    // 71
+    198, 198, 102,  58,   0,   0,   0,   0 },
+  {   0,   0, 198, 198, 198, 198, 254, 198,    // 72
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0,  60,  24,  24,  24,  24,  24,    // 73
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0,  30,  12,  12,  12,  12,  12,    // 74
+    204, 204, 204, 120,   0,   0,   0,   0 },
+  {   0,   0, 230, 102, 102, 108, 120, 120,    // 75
+    108, 102, 102, 230,   0,   0,   0,   0 },
+  {   0,   0, 240,  96,  96,  96,  96,  96,    // 76
+     96,  98, 102, 254,   0,   0,   0,   0 },
+  {   0,   0, 198, 238, 254, 254, 214, 198,    // 77
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0, 198, 230, 246, 254, 222, 206,    // 78
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198, 198, 198, 198,    // 79
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 252, 102, 102, 102, 124,  96,    // 80
+     96,  96,  96, 240,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198, 198, 198, 198,    // 81
+    198, 214, 222, 124,  12,  14,   0,   0 },
+  {   0,   0, 252, 102, 102, 102, 124, 108,    // 82
+    102, 102, 102, 230,   0,   0,   0,   0 },
+  {   0,   0, 124, 198, 198,  96,  56,  12,    // 83
+      6, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 126, 126,  90,  24,  24,  24,    // 84
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0, 198, 198, 198, 198, 198, 198,    // 85
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 198, 198, 198, 198, 198, 198,    // 86
+    198, 108,  56,  16,   0,   0,   0,   0 },
+  {   0,   0, 198, 198, 198, 198, 214, 214,    // 87
+    214, 254, 238, 108,   0,   0,   0,   0 },
+  {   0,   0, 198, 198, 108, 124,  56,  56,    // 88
+    124, 108, 198, 198,   0,   0,   0,   0 },
+  {   0,   0, 102, 102, 102, 102,  60,  24,    // 89
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0, 254, 198, 134,  12,  24,  48,    // 90
+     96, 194, 198, 254,   0,   0,   0,   0 },
+  {   0,   0,  60,  48,  48,  48,  48,  48,    // 91
+     48,  48,  48,  60,   0,   0,   0,   0 },
+  {   0,   0,   0, 128, 192, 224, 112,  56,    // 92
+     28,  14,   6,   2,   0,   0,   0,   0 },
+  {   0,   0,  60,  12,  12,  12,  12,  12,    // 93
+     12,  12,  12,  60,   0,   0,   0,   0 },
+  {  16,  56, 108, 198,   0,   0,   0,   0,    // 94
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 95
+      0,   0,   0,   0,   0, 255,   0,   0 },
+  {   0,  48,  24,  12,   0,   0,   0,   0,    // 96
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 120,  12, 124,    // 97
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0, 224,  96,  96, 120, 108, 102,    // 98
+    102, 102, 102, 124,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 198, 192,    // 99
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,  28,  12,  12,  60, 108, 204,    // 100
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 198, 254,    // 101
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,  28,  54,  50,  48, 120,  48,    // 102
+     48,  48,  48, 120,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 118, 204, 204,    // 103
+    204, 204, 204, 124,  12, 204, 120,   0 },
+  {   0,   0, 224,  96,  96, 108, 118, 102,    // 104
+    102, 102, 102, 230,   0,   0,   0,   0 },
+  {   0,   0,  24,  24,   0,  56,  24,  24,    // 105
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0,   6,   6,   0,  14,   6,   6,    // 106
+      6,   6,   6,   6, 102, 102,  60,   0 },
+  {   0,   0, 224,  96,  96, 102, 108, 120,    // 107
+    120, 108, 102, 230,   0,   0,   0,   0 },
+  {   0,   0,  56,  24,  24,  24,  24,  24,    // 108
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 236, 254, 214,    // 109
+    214, 214, 214, 198,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 220, 102, 102,    // 110
+    102, 102, 102, 102,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 198, 198,    // 111
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 220, 102, 102,    // 112
+    102, 102, 102, 124,  96,  96, 240,   0 },
+  {   0,   0,   0,   0,   0, 118, 204, 204,    // 113
+    204, 204, 204, 124,  12,  12,  30,   0 },
+  {   0,   0,   0,   0,   0, 220, 118, 102,    // 114
+     96,  96,  96, 240,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 198,  96,    // 115
+     56,  12, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,  16,  48,  48, 252,  48,  48,    // 116
+     48,  48,  54,  28,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 204, 204, 204,    // 117
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 198, 198, 198,    // 118
+    198, 198, 108,  56,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 198, 198, 214,    // 119
+    214, 214, 254, 108,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 198, 108,  56,    // 120
+     56,  56, 108, 198,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 198, 198, 198,    // 121
+    198, 198, 198, 126,   6,  12, 248,   0 },
+  {   0,   0,   0,   0,   0, 254, 204,  24,    // 122
+     48,  96, 198, 254,   0,   0,   0,   0 },
+  {   0,   0,  14,  24,  24,  24, 112,  24,    // 123
+     24,  24,  24,  14,   0,   0,   0,   0 },
+  {   0,   0,  24,  24,  24,  24,  24,  24,    // 124
+     24,  24,  24,  24,   0,   0,   0,   0 },
+  {   0,   0, 112,  24,  24,  24,  14,  24,    // 125
+     24,  24,  24, 112,   0,   0,   0,   0 },
+  {   0, 118, 220,   0,   0,   0,   0,   0,    // 126
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  16,  56, 108, 198,    // 127
+    198, 198, 254,   0,   0,   0,   0,   0 },
+  {   0,   0,  60, 102, 194, 192, 192, 192,    // 128
+    192, 194, 102,  60,  24, 112,   0,   0 },
+  {   0,   0, 204,   0,   0, 204, 204, 204,    // 129
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  12,  24,  48,   0, 124, 198, 254,    // 130
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,  16,  56, 108,   0, 120,  12, 124,    // 131
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0, 204,   0,   0, 120,  12, 124,    // 132
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  96,  48,  24,   0, 120,  12, 124,    // 133
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  56, 108,  56,   0, 120,  12, 124,    // 134
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 198, 192,    // 135
+    192, 192, 198, 124,  24, 112,   0,   0 },
+  {   0,  16,  56, 108,   0, 124, 198, 254,    // 136
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 198,   0,   0, 124, 198, 254,    // 137
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,  96,  48,  24,   0, 124, 198, 254,    // 138
+    192, 192, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 102,   0,   0,  56,  24,  24,    // 139
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,  24,  60, 102,   0,  56,  24,  24,    // 140
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,  96,  48,  24,   0,  56,  24,  24,    // 141
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0, 198,   0,  16,  56, 108, 198, 198,    // 142
+    254, 198, 198, 198,   0,   0,   0,   0 },
+  {  56, 108,  56,  16,  56, 108, 198, 198,    // 143
+    254, 198, 198, 198,   0,   0,   0,   0 },
+  {  12,  24,   0, 254, 102,  98, 104, 120,    // 144
+    104,  98, 102, 254,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 236,  54,  54,    // 145
+    126, 216, 216, 110,   0,   0,   0,   0 },
+  {   0,   0,  62, 108, 204, 204, 254, 204,    // 146
+    204, 204, 204, 206,   0,   0,   0,   0 },
+  {   0,  16,  56, 108,   0, 124, 198, 198,    // 147
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 198,   0,   0, 124, 198, 198,    // 148
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,  96,  48,  24,   0, 124, 198, 198,    // 149
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,  48, 120, 204,   0, 204, 204, 204,    // 150
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  96,  48,  24,   0, 204, 204, 204,    // 151
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0, 198,   0,   0, 198, 198, 198,    // 152
+    198, 198, 198, 126,   6,  12, 120,   0 },
+  {   0, 198,   0, 124, 198, 198, 198, 198,    // 153
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0, 198,   0, 198, 198, 198, 198, 198,    // 154
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 124, 206, 222,    // 155
+    246, 230, 198, 124,   0,   0,   0,   0 },
+  {   0,  56, 108, 100,  96, 240,  96,  96,    // 156
+     96,  96, 230, 252,   0,   0,   0,   0 },
+  {   0,   4, 124, 206, 206, 214, 214, 214,    // 157
+    214, 230, 230, 124,  64,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 198, 108,  56,    // 158
+     56, 108, 198,   0,   0,   0,   0,   0 },
+  {   0,  14,  27,  24,  24,  24, 126,  24,    // 159
+     24,  24, 216, 112,   0,   0,   0,   0 },
+  {   0,  24,  48,  96,   0, 120,  12, 124,    // 160
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,  12,  24,  48,   0,  56,  24,  24,    // 161
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0,  24,  48,  96,   0, 124, 198, 198,    // 162
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,  24,  48,  96,   0, 204, 204, 204,    // 163
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  {   0,   0, 118, 220,   0, 220, 102, 102,    // 164
+    102, 102, 102, 102,   0,   0,   0,   0 },
+  { 118, 220,   0, 198, 230, 246, 254, 222,    // 165
+    206, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0,  60, 108, 108,  62,   0, 126,    // 166
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,  56, 108, 108,  56,   0, 124,    // 167
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,  48,  48,   0,  48,  48,  96,    // 168
+    192, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 124, 130, 178, 170, 178, 170,    // 169
+    170, 130, 124,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0, 254,   6,    // 170
+      6,   6,   6,   0,   0,   0,   0,   0 },
+  {   0,  96, 224,  98, 102, 108,  24,  48,    // 171
+     96, 220, 134,  12,  24,  62,   0,   0 },
+  {   0,  96, 224,  98, 102, 108,  24,  48,    // 172
+    102, 206, 154,  63,   6,   6,   0,   0 },
+  {   0,   0,  24,  24,   0,  24,  24,  24,    // 173
+     60,  60,  60,  24,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  54, 108, 216,    // 174
+    108,  54,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 216, 108,  54,    // 175
+    108, 216,   0,   0,   0,   0,   0,   0 },
+  {  17,  68,  17,  68,  17,  68,  17,  68,    // 176
+     17,  68,  17,  68,  17,  68,  17,  68 },
+  {  85, 170,  85, 170,  85, 170,  85, 170,    // 177
+     85, 170,  85, 170,  85, 170,  85, 170 },
+  { 221, 119, 221, 119, 221, 119, 221, 119,    // 178
+    221, 119, 221, 119, 221, 119, 221, 119 },
+  {  24,  24,  24,  24,  24,  24,  24,  24,    // 179
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {  24,  24,  24,  24,  24,  24,  24, 248,    // 180
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {  96, 192,  16,  56, 108, 198, 198, 254,    // 181
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  { 124, 198,  16,  56, 108, 198, 198, 254,    // 182
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {  12,   6,  16,  56, 108, 198, 198, 254,    // 183
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {   0,   0, 124, 130, 154, 162, 162, 162,    // 184
+    154, 130, 124,   0,   0,   0,   0,   0 },
+  {  54,  54,  54,  54,  54, 246,   6, 246,    // 185
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {  54,  54,  54,  54,  54,  54,  54,  54,    // 186
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {   0,   0,   0,   0,   0, 254,   6, 246,    // 187
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {  54,  54,  54,  54,  54, 246,   6, 254,    // 188
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,  24,  24, 124, 198, 192, 192,    // 189
+    198, 124,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,   0, 102, 102,  60,  24, 126,    // 190
+     24, 126,  24,  24,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0, 248,    // 191
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {  24,  24,  24,  24,  24,  24,  24,  31,    // 192
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {  24,  24,  24,  24,  24,  24,  24, 255,    // 193
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0, 255,    // 194
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {  24,  24,  24,  24,  24,  24,  24,  31,    // 195
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {   0,   0,   0,   0,   0,   0,   0, 255,    // 196
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {  24,  24,  24,  24,  24,  24,  24, 255,    // 197
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  {   0,   0, 118, 220,   0, 120,  12, 124,    // 198
+    204, 204, 204, 118,   0,   0,   0,   0 },
+  { 118, 220,   0,  56, 108, 198, 198, 254,    // 199
+    198, 198, 198, 198,   0,   0,   0,   0 },
+  {  54,  54,  54,  54,  54,  55,  48,  63,    // 200
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  63,  48,  55,    // 201
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {  54,  54,  54,  54,  54, 247,   0, 255,    // 202
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 255,   0, 247,    // 203
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {  54,  54,  54,  54,  54,  55,  48,  55,    // 204
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {   0,   0,   0,   0,   0, 255,   0, 255,    // 205
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {  54,  54,  54,  54,  54, 247,   0, 247,    // 206
+     54,  54,  54,  54,  54,  54,  54,  54 },
+  {   0,   0,   0,   0, 198, 124, 198, 198,    // 207
+    198, 198, 124, 198,   0,   0,   0,   0 },
+  {   0,   0,  52,  24,  44,   6,  62, 102,    // 208
+    102, 102, 102,  60,   0,   0,   0,   0 },
+  {   0,   0, 248, 108, 102, 102, 246, 102,    // 209
+    102, 102, 108, 248,   0,   0,   0,   0 },
+  {  56, 108,   0, 254, 102,  98, 104, 120,    // 210
+    104,  98, 102, 254,   0,   0,   0,   0 },
+  {   0, 198,   0, 254, 102,  98, 104, 120,    // 211
+    104,  98, 102, 254,   0,   0,   0,   0 },
+  {  48,  24,   0, 254, 102,  98, 104, 120,    // 212
+    104,  98, 102, 254,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  56,  24,  24,    // 213
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {  12,  24,   0,  60,  24,  24,  24,  24,    // 214
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {  60, 102,   0,  60,  24,  24,  24,  24,    // 215
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0, 102,   0,  60,  24,  24,  24,  24,    // 216
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {  24,  24,  24,  24,  24,  24,  24, 248,    // 217
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,  31,    // 218
+     24,  24,  24,  24,  24,  24,  24,  24 },
+  { 255, 255, 255, 255, 255, 255, 255, 255,    // 219
+    255, 255, 255, 255, 255, 255, 255, 255 },
+  {   0,   0,   0,   0,   0,   0,   0, 255,    // 220
+    255, 255, 255, 255, 255, 255, 255, 255 },
+  {   0,  24,  24,  24,  24,  24,   0,   0,    // 221
+     24,  24,  24,  24,  24,   0,   0,   0 },
+  {  48,  24,   0,  60,  24,  24,  24,  24,    // 222
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  { 255, 255, 255, 255, 255, 255, 255,   0,    // 223
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {  24,  48,   0, 124, 198, 198, 198, 198,    // 224
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 120, 204, 204, 204, 216, 204,    // 225
+    198, 198, 198, 204,   0,   0,   0,   0 },
+  {  56, 108,   0, 124, 198, 198, 198, 198,    // 226
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {  48,  24,   0, 124, 198, 198, 198, 198,    // 227
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0, 118, 220,   0, 124, 198, 198,    // 228
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  { 118, 220,   0, 124, 198, 198, 198, 198,    // 229
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0, 102, 102, 102,    // 230
+    102, 102, 102, 124,  96,  96, 192,   0 },
+  {   0,   0, 224,  96,  96, 124, 102, 102,    // 231
+    102, 102, 102, 124,  96,  96, 240,   0 },
+  {   0,   0, 240,  96, 124, 102, 102, 102,    // 232
+    102, 124,  96, 240,   0,   0,   0,   0 },
+  {  24,  48,   0, 198, 198, 198, 198, 198,    // 233
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {  56, 108,   0, 198, 198, 198, 198, 198,    // 234
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {  48,  24,   0, 198, 198, 198, 198, 198,    // 235
+    198, 198, 198, 124,   0,   0,   0,   0 },
+  {   0,  12,  24,  48,   0, 198, 198, 198,    // 236
+    198, 198, 198, 126,   6,  12, 248,   0 },
+  {  12,  24,   0, 102, 102, 102, 102,  60,    // 237
+     24,  24,  24,  60,   0,   0,   0,   0 },
+  {   0, 255,   0,   0,   0,   0,   0,   0,    // 238
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,  12,  24,  48,   0,   0,   0,   0,    // 239
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0, 254,    // 240
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,  24,  24, 126,  24,    // 241
+     24,   0,   0, 126,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 242
+      0,   0,   0,   0, 255,   0, 255,   0 },
+  {   0, 224,  48,  98,  54, 236,  24,  48,    // 243
+    102, 206, 154,  63,   6,   6,   0,   0 },
+  {   0,   0, 127, 219, 219, 219, 123,  27,    // 244
+     27,  27,  27,  27,   0,   0,   0,   0 },
+  {   0, 124, 198,  96,  56, 108, 198, 198,    // 245
+    108,  56,  12, 198, 124,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,  24,   0, 126,    // 246
+      0,  24,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 247
+      0,   0,   0,  24,  12, 120,   0,   0 },
+  {   0,  56, 108, 108,  56,   0,   0,   0,    // 248
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0, 198,   0,   0,   0,   0,   0,   0,    // 249
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,  24,    // 250
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,  24,  56,  24,  24,  24,  60,   0,    // 251
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0, 124,   6,  60,   6,   6, 124,   0,    // 252
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,  60, 102,  12,  24,  50, 126,   0,    // 253
+      0,   0,   0,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0, 126, 126, 126, 126,    // 254
+    126, 126, 126,   0,   0,   0,   0,   0 },
+  {   0,   0,   0,   0,   0,   0,   0,   0,    // 255
+      0,   0,   0,   0,   0,   0,   0,   0 }};
+
+unsigned char sdl_font8x8[256][8] = {
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 0
+  { 126, 129, 165, 129, 189, 153, 129, 126 },  // 1
+  { 126, 255, 219, 255, 195, 231, 255, 126 },  // 2
+  { 108, 254, 254, 254, 124,  56,  16,   0 },  // 3
+  {  16,  56, 124, 254, 124,  56,  16,   0 },  // 4
+  {  56, 124,  56, 254, 254, 214,  16,  56 },  // 5
+  {  16,  56, 124, 254, 254, 124,  16,  56 },  // 6
+  {   0,   0,  24,  60,  60,  24,   0,   0 },  // 7
+  { 255, 255, 231, 195, 195, 231, 255, 255 },  // 8
+  {   0,  60, 102,  66,  66, 102,  60,   0 },  // 9
+  { 255, 195, 153, 189, 189, 153, 195, 255 },  // 10
+  {  15,   7,  15, 125, 204, 204, 204, 120 },  // 11
+  {  60, 102, 102, 102,  60,  24, 126,  24 },  // 12
+  {  63,  51,  63,  48,  48, 112, 240, 224 },  // 13
+  { 127,  99, 127,  99,  99, 103, 230, 192 },  // 14
+  {  24, 219,  60, 231, 231,  60, 219,  24 },  // 15
+  { 128, 224, 248, 254, 248, 224, 128,   0 },  // 16
+  {   2,  14,  62, 254,  62,  14,   2,   0 },  // 17
+  {  24,  60, 126,  24,  24, 126,  60,  24 },  // 18
+  { 102, 102, 102, 102, 102,   0, 102,   0 },  // 19
+  { 127, 219, 219, 123,  27,  27,  27,   0 },  // 20
+  {  62,  97,  60, 102, 102,  60, 134, 124 },  // 21
+  {   0,   0,   0,   0, 126, 126, 126,   0 },  // 22
+  {  24,  60, 126,  24, 126,  60,  24, 255 },  // 23
+  {  24,  60, 126,  24,  24,  24,  24,   0 },  // 24
+  {  24,  24,  24,  24, 126,  60,  24,   0 },  // 25
+  {   0,  24,  12, 254,  12,  24,   0,   0 },  // 26
+  {   0,  48,  96, 254,  96,  48,   0,   0 },  // 27
+  {   0,   0, 192, 192, 192, 254,   0,   0 },  // 28
+  {   0,  36, 102, 255, 102,  36,   0,   0 },  // 29
+  {   0,  24,  60, 126, 255, 255,   0,   0 },  // 30
+  {   0, 255, 255, 126,  60,  24,   0,   0 },  // 31
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 32
+  {  24,  60,  60,  24,  24,   0,  24,   0 },  // 33
+  { 102, 102,  36,   0,   0,   0,   0,   0 },  // 34
+  { 108, 108, 254, 108, 254, 108, 108,   0 },  // 35
+  {  24,  62,  96,  60,   6, 124,  24,   0 },  // 36
+  {   0, 198, 204,  24,  48, 102, 198,   0 },  // 37
+  {  56, 108,  56, 118, 220, 204, 118,   0 },  // 38
+  {  24,  24,  48,   0,   0,   0,   0,   0 },  // 39
+  {  12,  24,  48,  48,  48,  24,  12,   0 },  // 40
+  {  48,  24,  12,  12,  12,  24,  48,   0 },  // 41
+  {   0, 102,  60, 231,  60, 102,   0,   0 },  // 42
+  {   0,  24,  24, 126,  24,  24,   0,   0 },  // 43
+  {   0,   0,   0,   0,   0,  24,  24,  48 },  // 44
+  {   0,   0,   0, 126,   0,   0,   0,   0 },  // 45
+  {   0,   0,   0,   0,   0,  24,  24,   0 },  // 46
+  {   6,  12,  24,  48,  96, 192, 128,   0 },  // 47
+  { 124, 198, 206, 222, 246, 230, 124,   0 },  // 48
+  {  24,  56,  24,  24,  24,  24, 126,   0 },  // 49
+  { 124, 198,   6,  28,  48, 102, 254,   0 },  // 50
+  { 124, 198,   6,  60,   6, 198, 124,   0 },  // 51
+  {  28,  60, 108, 204, 254,  12,  30,   0 },  // 52
+  { 254, 192, 192, 252,   6, 198, 124,   0 },  // 53
+  {  56,  96, 192, 252, 198, 198, 124,   0 },  // 54
+  { 254, 198,  12,  24,  48,  48,  48,   0 },  // 55
+  { 124, 198, 198, 124, 198, 198, 124,   0 },  // 56
+  { 124, 198, 198, 126,   6,  12, 120,   0 },  // 57
+  {   0,  24,  24,   0,   0,  24,  24,   0 },  // 58
+  {   0,  24,  24,   0,   0,  24,  24,  48 },  // 59
+  {   6,  12,  24,  48,  24,  12,   6,   0 },  // 60
+  {   0,   0, 126,   0,   0, 126,   0,   0 },  // 61
+  {  96,  48,  24,  12,  24,  48,  96,   0 },  // 62
+  { 124, 198,  12,  24,  24,   0,  24,   0 },  // 63
+  { 124, 198, 222, 222, 222, 192, 120,   0 },  // 64
+  {  56, 108, 198, 254, 198, 198, 198,   0 },  // 65
+  { 252, 102, 102, 124, 102, 102, 252,   0 },  // 66
+  {  60, 102, 192, 192, 192, 102,  60,   0 },  // 67
+  { 248, 108, 102, 102, 102, 108, 248,   0 },  // 68
+  { 254,  98, 104, 120, 104,  98, 254,   0 },  // 69
+  { 254,  98, 104, 120, 104,  96, 240,   0 },  // 70
+  {  60, 102, 192, 192, 206, 102,  58,   0 },  // 71
+  { 198, 198, 198, 254, 198, 198, 198,   0 },  // 72
+  {  60,  24,  24,  24,  24,  24,  60,   0 },  // 73
+  {  30,  12,  12,  12, 204, 204, 120,   0 },  // 74
+  { 230, 102, 108, 120, 108, 102, 230,   0 },  // 75
+  { 240,  96,  96,  96,  98, 102, 254,   0 },  // 76
+  { 198, 238, 254, 254, 214, 198, 198,   0 },  // 77
+  { 198, 230, 246, 222, 206, 198, 198,   0 },  // 78
+  { 124, 198, 198, 198, 198, 198, 124,   0 },  // 79
+  { 252, 102, 102, 124,  96,  96, 240,   0 },  // 80
+  { 124, 198, 198, 198, 198, 206, 124,  14 },  // 81
+  { 252, 102, 102, 124, 108, 102, 230,   0 },  // 82
+  {  60, 102,  48,  24,  12, 102,  60,   0 },  // 83
+  { 126, 126,  90,  24,  24,  24,  60,   0 },  // 84
+  { 198, 198, 198, 198, 198, 198, 124,   0 },  // 85
+  { 198, 198, 198, 198, 198, 108,  56,   0 },  // 86
+  { 198, 198, 198, 214, 214, 254, 108,   0 },  // 87
+  { 198, 198, 108,  56, 108, 198, 198,   0 },  // 88
+  { 102, 102, 102,  60,  24,  24,  60,   0 },  // 89
+  { 254, 198, 140,  24,  50, 102, 254,   0 },  // 90
+  {  60,  48,  48,  48,  48,  48,  60,   0 },  // 91
+  { 192,  96,  48,  24,  12,   6,   2,   0 },  // 92
+  {  60,  12,  12,  12,  12,  12,  60,   0 },  // 93
+  {  16,  56, 108, 198,   0,   0,   0,   0 },  // 94
+  {   0,   0,   0,   0,   0,   0,   0, 255 },  // 95
+  {  48,  24,  12,   0,   0,   0,   0,   0 },  // 96
+  {   0,   0, 120,  12, 124, 204, 118,   0 },  // 97
+  { 224,  96, 124, 102, 102, 102, 220,   0 },  // 98
+  {   0,   0, 124, 198, 192, 198, 124,   0 },  // 99
+  {  28,  12, 124, 204, 204, 204, 118,   0 },  // 100
+  {   0,   0, 124, 198, 254, 192, 124,   0 },  // 101
+  {  60, 102,  96, 248,  96,  96, 240,   0 },  // 102
+  {   0,   0, 118, 204, 204, 124,  12, 248 },  // 103
+  { 224,  96, 108, 118, 102, 102, 230,   0 },  // 104
+  {  24,   0,  56,  24,  24,  24,  60,   0 },  // 105
+  {   6,   0,   6,   6,   6, 102, 102,  60 },  // 106
+  { 224,  96, 102, 108, 120, 108, 230,   0 },  // 107
+  {  56,  24,  24,  24,  24,  24,  60,   0 },  // 108
+  {   0,   0, 236, 254, 214, 214, 214,   0 },  // 109
+  {   0,   0, 220, 102, 102, 102, 102,   0 },  // 110
+  {   0,   0, 124, 198, 198, 198, 124,   0 },  // 111
+  {   0,   0, 220, 102, 102, 124,  96, 240 },  // 112
+  {   0,   0, 118, 204, 204, 124,  12,  30 },  // 113
+  {   0,   0, 220, 118,  96,  96, 240,   0 },  // 114
+  {   0,   0, 126, 192, 124,   6, 252,   0 },  // 115
+  {  48,  48, 252,  48,  48,  54,  28,   0 },  // 116
+  {   0,   0, 204, 204, 204, 204, 118,   0 },  // 117
+  {   0,   0, 198, 198, 198, 108,  56,   0 },  // 118
+  {   0,   0, 198, 214, 214, 254, 108,   0 },  // 119
+  {   0,   0, 198, 108,  56, 108, 198,   0 },  // 120
+  {   0,   0, 198, 198, 198, 126,   6, 252 },  // 121
+  {   0,   0, 126,  76,  24,  50, 126,   0 },  // 122
+  {  14,  24,  24, 112,  24,  24,  14,   0 },  // 123
+  {  24,  24,  24,  24,  24,  24,  24,   0 },  // 124
+  { 112,  24,  24,  14,  24,  24, 112,   0 },  // 125
+  { 118, 220,   0,   0,   0,   0,   0,   0 },  // 126
+  {   0,  16,  56, 108, 198, 198, 254,   0 },  // 127
+  { 124, 198, 192, 192, 198, 124,  12, 120 },  // 128
+  { 204,   0, 204, 204, 204, 204, 118,   0 },  // 129
+  {  12,  24, 124, 198, 254, 192, 124,   0 },  // 130
+  { 124, 130, 120,  12, 124, 204, 118,   0 },  // 131
+  { 198,   0, 120,  12, 124, 204, 118,   0 },  // 132
+  {  48,  24, 120,  12, 124, 204, 118,   0 },  // 133
+  {  48,  48, 120,  12, 124, 204, 118,   0 },  // 134
+  {   0,   0, 126, 192, 192, 126,  12,  56 },  // 135
+  { 124, 130, 124, 198, 254, 192, 124,   0 },  // 136
+  { 198,   0, 124, 198, 254, 192, 124,   0 },  // 137
+  {  48,  24, 124, 198, 254, 192, 124,   0 },  // 138
+  { 102,   0,  56,  24,  24,  24,  60,   0 },  // 139
+  { 124, 130,  56,  24,  24,  24,  60,   0 },  // 140
+  {  48,  24,   0,  56,  24,  24,  60,   0 },  // 141
+  { 198,  56, 108, 198, 254, 198, 198,   0 },  // 142
+  {  56, 108, 124, 198, 254, 198, 198,   0 },  // 143
+  {  24,  48, 254, 192, 248, 192, 254,   0 },  // 144
+  {   0,   0, 126,  18, 254, 144, 254,   0 },  // 145
+  {  62, 108, 204, 254, 204, 204, 206,   0 },  // 146
+  { 124, 130, 124, 198, 198, 198, 124,   0 },  // 147
+  { 198,   0, 124, 198, 198, 198, 124,   0 },  // 148
+  {  48,  24, 124, 198, 198, 198, 124,   0 },  // 149
+  { 120, 132,   0, 204, 204, 204, 118,   0 },  // 150
+  {  96,  48, 204, 204, 204, 204, 118,   0 },  // 151
+  { 198,   0, 198, 198, 198, 126,   6, 252 },  // 152
+  { 198,  56, 108, 198, 198, 108,  56,   0 },  // 153
+  { 198,   0, 198, 198, 198, 198, 124,   0 },  // 154
+  {   0,   2, 124, 206, 214, 230, 124, 128 },  // 155
+  {  56, 108, 100, 240,  96, 102, 252,   0 },  // 156
+  {  58, 108, 206, 214, 230, 108, 184,   0 },  // 157
+  {   0, 198, 108,  56, 108, 198,   0,   0 },  // 158
+  {  14,  27,  24,  60,  24, 216, 112,   0 },  // 159
+  {  24,  48, 120,  12, 124, 204, 118,   0 },  // 160
+  {  12,  24,   0,  56,  24,  24,  60,   0 },  // 161
+  {  12,  24, 124, 198, 198, 198, 124,   0 },  // 162
+  {  24,  48, 204, 204, 204, 204, 118,   0 },  // 163
+  { 118, 220,   0, 220, 102, 102, 102,   0 },  // 164
+  { 118, 220,   0, 230, 246, 222, 206,   0 },  // 165
+  {  60, 108, 108,  62,   0, 126,   0,   0 },  // 166
+  {  56, 108, 108,  56,   0, 124,   0,   0 },  // 167
+  {  24,   0,  24,  24,  48,  99,  62,   0 },  // 168
+  { 126, 129, 185, 165, 185, 165, 129, 126 },  // 169
+  {   0,   0,   0, 254,   6,   6,   0,   0 },  // 170
+  {  99, 230, 108, 126,  51, 102, 204,  15 },  // 171
+  {  99, 230, 108, 122,  54, 106, 223,   6 },  // 172
+  {  24,   0,  24,  24,  60,  60,  24,   0 },  // 173
+  {   0,  51, 102, 204, 102,  51,   0,   0 },  // 174
+  {   0, 204, 102,  51, 102, 204,   0,   0 },  // 175
+  {  34, 136,  34, 136,  34, 136,  34, 136 },  // 176
+  {  85, 170,  85, 170,  85, 170,  85, 170 },  // 177
+  { 119, 221, 119, 221, 119, 221, 119, 221 },  // 178
+  {  24,  24,  24,  24,  24,  24,  24,  24 },  // 179
+  {  24,  24,  56, 248,  56,  24,  24,  24 },  // 180
+  {  48,  96,  56, 108, 198, 254, 198,   0 },  // 181
+  { 124, 130,  56, 108, 198, 254, 198,   0 },  // 182
+  {  24,  12,  56, 108, 198, 254, 198,   0 },  // 183
+  { 126, 129, 157, 161, 161, 157, 129, 126 },  // 184
+  {  54,  54, 246,   6, 246,  54,  54,  54 },  // 185
+  {  54,  54,  54,  54,  54,  54,  54,  54 },  // 186
+  {   0,   0, 254,   6, 246,  54,  54,  54 },  // 187
+  {  54,  54, 246,   6, 254,   0,   0,   0 },  // 188
+  {  24,  24, 126, 192, 192, 126,  24,  24 },  // 189
+  { 102, 102,  60, 126,  24, 126,  24,  24 },  // 190
+  {   0,   0,   0, 240,  56,  24,  24,  24 },  // 191
+  {  24,  24,  28,  15,   0,   0,   0,   0 },  // 192
+  {  24,  24,  60, 255,   0,   0,   0,   0 },  // 193
+  {   0,   0,   0, 255,  60,  24,  24,  24 },  // 194
+  {  48,  48,  56,  63,  56,  48,  48,  48 },  // 195
+  {   0,   0,   0, 255,   0,   0,   0,   0 },  // 196
+  {  24,  24,  24,  60, 231,  60,  24,  24 },  // 197
+  { 240, 120, 120, 120,  60,  60,  60,  28 },  // 198
+  {  30,  60,  60,  60, 120, 120, 120, 112 },  // 199
+  {  15,  63,  63, 120, 120,   0,   1,   3 },  // 200
+  { 192, 224, 240, 240, 240, 240, 240, 224 },  // 201
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 202
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 203
+  {  30,  30,  14,  15,  15,   7,   7,   0 },  // 204
+  { 240, 240, 224, 224, 192, 192, 192,   0 },  // 205
+  {   6,  13,  27,  55,  47, 127, 126,  30 },  // 206
+  {   0, 252, 255, 255, 143, 119, 243,   3 },  // 207
+  {   0,   1,   7, 143, 143, 207, 207, 199 },  // 208
+  {   0, 248, 254, 254,  31,  15, 192, 248 },  // 209
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 210
+  {   0,   0,   0,   0,   0,   0,   0,   0 },  // 211
+  {  30,  30,  30,  31,  15,   7,   7,   1 },  // 212
+  {   3,   3,   3,   7, 143, 255, 254, 252 },  // 213
+  { 195, 192, 192, 207, 143,   7,   7,   1 },  // 214
+  { 254, 255,  31,  15, 143, 254, 254, 248 },  // 215
+  { 102,   0,  60,  24,  24,  24,  60,   0 },  // 216
+  {  24,  24,  56, 240,   0,   0,   0,   0 },  // 217
+  {   0,   0,   0,  15,  28,  24,  24,  24 },  // 218
+  { 255, 255, 255, 255, 255, 255, 255, 255 },  // 219
+  {   0,   0,   0,   0, 255, 255, 255, 255 },  // 220
+  {  24,  24,  24,   0,   0,  24,  24,  24 },  // 221
+  {  48,  24,  60,  24,  24,  24,  60,   0 },  // 222
+  { 255, 255, 255, 255,   0,   0,   0,   0 },  // 223
+  {   0,   0,   0,   0,   0,   0,   0, 255 },  // 224
+  {   0,   0,   0,   0,   0, 255,   0, 255 },  // 225
+  {   0,   0,   0, 255,   0, 255,   0, 255 },  // 226
+  {   0, 255,   0, 255,   0, 255,   0, 255 },  // 227
+  {   0, 255,   0, 255,   0, 255,   0,   0 },  // 228
+  {   0, 255,   0, 255,   0,   0,   0,   0 },  // 229
+  {   0, 255,   0,   0,   0,   0,   0,   0 },  // 230
+  { 224, 128,   0,   0,   0,   0, 128, 224 },  // 231
+  { 248, 254, 255, 255, 255, 255, 254, 248 },  // 232
+  {  24,  48, 198, 198, 198, 198, 124,   0 },  // 233
+  { 124, 130,   0, 198, 198, 198, 124,   0 },  // 234
+  {  96,  48, 198, 198, 198, 198, 124,   0 },  // 235
+  {  24,  48, 198, 198, 198, 126,   6, 252 },  // 236
+  {  12,  24, 102, 102,  60,  24,  60,   0 },  // 237
+  { 255,   0,   0,   0,   0,   0,   0,   0 },  // 238
+  {  12,  24,  48,   0,   0,   0,   0,   0 },  // 239
+  {   0,   0,   0, 126,   0,   0,   0,   0 },  // 240
+  {  24,  24, 126,  24,  24,   0, 126,   0 },  // 241
+  {   0,   0,   0,   0,   0, 255,   0, 255 },  // 242
+  { 225,  50, 228,  58, 246,  42,  95, 134 },  // 243
+  { 127, 219, 219, 123,  27,  27,  27,   0 },  // 244
+  {  62,  97,  60, 102, 102,  60, 134, 124 },  // 245
+  {   0,  24,   0, 126,   0,  24,   0,   0 },  // 246
+  {   0,   0,   0,   0,   0,  24,  12,  56 },  // 247
+  {  56, 108, 108,  56,   0,   0,   0,   0 },  // 248
+  {   0, 198,   0,   0,   0,   0,   0,   0 },  // 249
+  {   0,   0,   0,  24,   0,   0,   0,   0 },  // 250
+  {  24,  56,  24,  24,  60,   0,   0,   0 },  // 251
+  { 120,  12,  56,  12, 120,   0,   0,   0 },  // 252
+  { 120,  12,  24,  48, 124,   0,   0,   0 },  // 253
+  {   0,   0,  60,  60,  60,  60,   0,   0 },  // 254
+  {   0,   0,   0,   0,   0,   0,   0,   0 }}; // 255
+
+/*
+unsigned char sdl_palette[256][3] = {
+  {   0,   0,   0 },  // 0
+  {   0,   0, 168 },  // 1
+  {   0, 168,   0 },  // 2
+  {   0, 168, 168 },  // 3
+  { 168,   0,   0 },  // 4
+  { 168,   0, 168 },  // 5
+  { 168,  84,   0 },  // 6
+  { 168, 168, 168 },  // 7
+  {  84,  84,  84 },  // 8
+  {  84,  84, 252 },  // 9
+  {  84, 252,  84 },  // 10
+  {  84, 252, 252 },  // 11
+  { 252,  84,  84 },  // 12
+  { 252,  84, 252 },  // 13
+  { 252, 252,  84 },  // 14
+  { 252, 252, 252 },  // 15
+  {   0,   0,   0 },  // 16
+  {  20,  20,  20 },  // 17
+  {  32,  32,  32 },  // 18
+  {  44,  44,  44 },  // 19
+  {  56,  56,  56 },  // 20
+  {  68,  68,  68 },  // 21
+  {  80,  80,  80 },  // 22
+  {  96,  96,  96 },  // 23
+  { 112, 112, 112 },  // 24
+  { 128, 128, 128 },  // 25
+  { 144, 144, 144 },  // 26
+  { 160, 160, 160 },  // 27
+  { 180, 180, 180 },  // 28
+  { 200, 200, 200 },  // 29
+  { 224, 224, 224 },  // 30
+  { 252, 252, 252 },  // 31
+  {   0,   0, 252 },  // 32
+  {  64,   0, 252 },  // 33
+  { 124,   0, 252 },  // 34
+  { 188,   0, 252 },  // 35
+  { 252,   0, 252 },  // 36
+  { 252,   0, 188 },  // 37
+  { 252,   0, 124 },  // 38
+  { 252,   0,  64 },  // 39
+  { 252,   0,   0 },  // 40
+  { 252,  64,   0 },  // 41
+  { 252, 124,   0 },  // 42
+  { 252, 188,   0 },  // 43
+  { 252, 252,   0 },  // 44
+  { 188, 252,   0 },  // 45
+  { 124, 252,   0 },  // 46
+  {  64, 252,   0 },  // 47
+  {   0, 252,   0 },  // 48
+  {   0, 252,  64 },  // 49
+  {   0, 252, 124 },  // 50
+  {   0, 252, 188 },  // 51
+  {   0, 252, 252 },  // 52
+  {   0, 188, 252 },  // 53
+  {   0, 124, 252 },  // 54
+  {   0,  64, 252 },  // 55
+  { 124, 124, 252 },  // 56
+  { 156, 124, 252 },  // 57
+  { 188, 124, 252 },  // 58
+  { 220, 124, 252 },  // 59
+  { 252, 124, 252 },  // 60
+  { 252, 124, 220 },  // 61
+  { 252, 124, 188 },  // 62
+  { 252, 124, 156 },  // 63
+  { 252, 124, 124 },  // 64
+  { 252, 156, 124 },  // 65
+  { 252, 188, 124 },  // 66
+  { 252, 220, 124 },  // 67
+  { 252, 252, 124 },  // 68
+  { 220, 252, 124 },  // 69
+  { 188, 252, 124 },  // 70
+  { 156, 252, 124 },  // 71
+  { 124, 252, 124 },  // 72
+  { 124, 252, 156 },  // 73
+  { 124, 252, 188 },  // 74
+  { 124, 252, 220 },  // 75
+  { 124, 252, 252 },  // 76
+  { 124, 220, 252 },  // 77
+  { 124, 188, 252 },  // 78
+  { 124, 156, 252 },  // 79
+  { 180, 180, 252 },  // 80
+  { 196, 180, 252 },  // 81
+  { 216, 180, 252 },  // 82
+  { 232, 180, 252 },  // 83
+  { 252, 180, 252 },  // 84
+  { 252, 180, 232 },  // 85
+  { 252, 180, 216 },  // 86
+  { 252, 180, 196 },  // 87
+  { 252, 180, 180 },  // 88
+  { 252, 196, 180 },  // 89
+  { 252, 216, 180 },  // 90
+  { 252, 232, 180 },  // 91
+  { 252, 252, 180 },  // 92
+  { 232, 252, 180 },  // 93
+  { 216, 252, 180 },  // 94
+  { 196, 252, 180 },  // 95
+  { 180, 252, 180 },  // 96
+  { 180, 252, 196 },  // 97
+  { 180, 252, 216 },  // 98
+  { 180, 252, 232 },  // 99
+  { 180, 252, 252 },  // 100
+  { 180, 232, 252 },  // 101
+  { 180, 216, 252 },  // 102
+  { 180, 196, 252 },  // 103
+  {   0,   0, 112 },  // 104
+  {  28,   0, 112 },  // 105
+  {  56,   0, 112 },  // 106
+  {  84,   0, 112 },  // 107
+  { 112,   0, 112 },  // 108
+  { 112,   0,  84 },  // 109
+  { 112,   0,  56 },  // 110
+  { 112,   0,  28 },  // 111
+  { 112,   0,   0 },  // 112
+  { 112,  28,   0 },  // 113
+  { 112,  56,   0 },  // 114
+  { 112,  84,   0 },  // 115
+  { 112, 112,   0 },  // 116
+  {  84, 112,   0 },  // 117
+  {  56, 112,   0 },  // 118
+  {  28, 112,   0 },  // 119
+  {   0, 112,   0 },  // 120
+  {   0, 112,  28 },  // 121
+  {   0, 112,  56 },  // 122
+  {   0, 112,  84 },  // 123
+  {   0, 112, 112 },  // 124
+  {   0,  84, 112 },  // 125
+  {   0,  56, 112 },  // 126
+  {   0,  28, 112 },  // 127
+  {  56,  56, 112 },  // 128
+  {  68,  56, 112 },  // 129
+  {  84,  56, 112 },  // 130
+  {  96,  56, 112 },  // 131
+  { 112,  56, 112 },  // 132
+  { 112,  56,  96 },  // 133
+  { 112,  56,  84 },  // 134
+  { 112,  56,  68 },  // 135
+  { 112,  56,  56 },  // 136
+  { 112,  68,  56 },  // 137
+  { 112,  84,  56 },  // 138
+  { 112,  96,  56 },  // 139
+  { 112, 112,  56 },  // 140
+  {  96, 112,  56 },  // 141
+  {  84, 112,  56 },  // 142
+  {  68, 112,  56 },  // 143
+  {  56, 112,  56 },  // 144
+  {  56, 112,  68 },  // 145
+  {  56, 112,  84 },  // 146
+  {  56, 112,  96 },  // 147
+  {  56, 112, 112 },  // 148
+  {  56,  96, 112 },  // 149
+  {  56,  84, 112 },  // 150
+  {  56,  68, 112 },  // 151
+  {  80,  80, 112 },  // 152
+  {  88,  80, 112 },  // 153
+  {  96,  80, 112 },  // 154
+  { 104,  80, 112 },  // 155
+  { 112,  80, 112 },  // 156
+  { 112,  80, 104 },  // 157
+  { 112,  80,  96 },  // 158
+  { 112,  80,  88 },  // 159
+  { 112,  80,  80 },  // 160
+  { 112,  88,  80 },  // 161
+  { 112,  96,  80 },  // 162
+  { 112, 104,  80 },  // 163
+  { 112, 112,  80 },  // 164
+  { 104, 112,  80 },  // 165
+  {  96, 112,  80 },  // 166
+  {  88, 112,  80 },  // 167
+  {  80, 112,  80 },  // 168
+  {  80, 112,  88 },  // 169
+  {  80, 112,  96 },  // 170
+  {  80, 112, 104 },  // 171
+  {  80, 112, 112 },  // 172
+  {  80, 104, 112 },  // 173
+  {  80,  96, 112 },  // 174
+  {  80,  88, 112 },  // 175
+  {   0,   0,  64 },  // 176
+  {  16,   0,  64 },  // 177
+  {  32,   0,  64 },  // 178
+  {  48,   0,  64 },  // 179
+  {  64,   0,  64 },  // 180
+  {  64,   0,  48 },  // 181
+  {  64,   0,  32 },  // 182
+  {  64,   0,  16 },  // 183
+  {  64,   0,   0 },  // 184
+  {  64,  16,   0 },  // 185
+  {  64,  32,   0 },  // 186
+  {  64,  48,   0 },  // 187
+  {  64,  64,   0 },  // 188
+  {  48,  64,   0 },  // 189
+  {  32,  64,   0 },  // 190
+  {  16,  64,   0 },  // 191
+  {   0,  64,   0 },  // 192
+  {   0,  64,  16 },  // 193
+  {   0,  64,  32 },  // 194
+  {   0,  64,  48 },  // 195
+  {   0,  64,  64 },  // 196
+  {   0,  48,  64 },  // 197
+  {   0,  32,  64 },  // 198
+  {   0,  16,  64 },  // 199
+  {  32,  32,  64 },  // 200
+  {  40,  32,  64 },  // 201
+  {  48,  32,  64 },  // 202
+  {  56,  32,  64 },  // 203
+  {  64,  32,  64 },  // 204
+  {  64,  32,  56 },  // 205
+  {  64,  32,  48 },  // 206
+  {  64,  32,  40 },  // 207
+  {  64,  32,  32 },  // 208
+  {  64,  40,  32 },  // 209
+  {  64,  48,  32 },  // 210
+  {  64,  56,  32 },  // 211
+  {  64,  64,  32 },  // 212
+  {  56,  64,  32 },  // 213
+  {  48,  64,  32 },  // 214
+  {  40,  64,  32 },  // 215
+  {  32,  64,  32 },  // 216
+  {  32,  64,  40 },  // 217
+  {  32,  64,  48 },  // 218
+  {  32,  64,  56 },  // 219
+  {  32,  64,  64 },  // 220
+  {  32,  56,  64 },  // 221
+  {  32,  48,  64 },  // 222
+  {  32,  40,  64 },  // 223
+  {  44,  44,  64 },  // 224
+  {  48,  44,  64 },  // 225
+  {  52,  44,  64 },  // 226
+  {  60,  44,  64 },  // 227
+  {  64,  44,  64 },  // 228
+  {  64,  44,  60 },  // 229
+  {  64,  44,  52 },  // 230
+  {  64,  44,  48 },  // 231
+  {  64,  44,  44 },  // 232
+  {  64,  48,  44 },  // 233
+  {  64,  52,  44 },  // 234
+  {  64,  60,  44 },  // 235
+  {  64,  64,  44 },  // 236
+  {  60,  64,  44 },  // 237
+  {  52,  64,  44 },  // 238
+  {  48,  64,  44 },  // 239
+  {  44,  64,  44 },  // 240
+  {  44,  64,  48 },  // 241
+  {  44,  64,  52 },  // 242
+  {  44,  64,  60 },  // 243
+  {  44,  64,  64 },  // 244
+  {  44,  60,  64 },  // 245
+  {  44,  52,  64 },  // 246
+  {  44,  48,  64 },  // 247
+  {   0,   0,   0 },  // 248
+  {   0,   0,   0 },  // 249
+  {   0,   0,   0 },  // 250
+  {   0,   0,   0 },  // 251
+  {   0,   0,   0 },  // 252
+  {   0,   0,   0 },  // 253
+  {   0,   0,   0 },  // 254
+  { 112,  97, 108 }}; // 255
+*/
diff --git a/tools/ioemu/gui/sdlkeys.h b/tools/ioemu/gui/sdlkeys.h
new file mode 100644 (file)
index 0000000..fd1197a
--- /dev/null
@@ -0,0 +1,257 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: sdlkeys.h,v 1.2 2002/10/24 21:06:32 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file is simply a list of SDL key symbols taken from <SDL/SDL_keysym.h>.
+// The order in this file is not important.  In sdl.cc, DEF_SDL_KEY() is
+// defined as a macro and then it includes this file to fill in all the data in
+// its key mapping table.
+// 
+// The symbols, such as SDLK_RETURN, are used for two purposes.  They
+// are converted into a string (by the # operator in processor), which is 
+// compared to the host key name in the keymap file.  Also, the value of
+// the symbol is inserted into the key mapping table.  Then the value is
+// compared with the keysym field of each key up/down event as it arrives.
+// 
+// If you get undefined symbol errors in this file, it must mean that
+// your SDL library version doesn't define those same SDLK_* symbols in
+// <SDL/SDL_keysym.h>.  You can't fix it with #ifdef SDLK_SYM because
+// they are enums, so you'll just have to comment out the offending line.
+// The list was generated using symbols from SDL 1.2.3.
+
+DEF_SDL_KEY( SDLK_UNKNOWN )
+DEF_SDL_KEY( SDLK_FIRST )
+DEF_SDL_KEY( SDLK_BACKSPACE )
+DEF_SDL_KEY( SDLK_TAB )
+DEF_SDL_KEY( SDLK_CLEAR )
+DEF_SDL_KEY( SDLK_RETURN )
+DEF_SDL_KEY( SDLK_PAUSE )
+DEF_SDL_KEY( SDLK_ESCAPE )
+DEF_SDL_KEY( SDLK_SPACE )
+DEF_SDL_KEY( SDLK_EXCLAIM )
+DEF_SDL_KEY( SDLK_QUOTEDBL )
+DEF_SDL_KEY( SDLK_HASH )
+DEF_SDL_KEY( SDLK_DOLLAR )
+DEF_SDL_KEY( SDLK_AMPERSAND )
+DEF_SDL_KEY( SDLK_QUOTE )
+DEF_SDL_KEY( SDLK_LEFTPAREN )
+DEF_SDL_KEY( SDLK_RIGHTPAREN )
+DEF_SDL_KEY( SDLK_ASTERISK )
+DEF_SDL_KEY( SDLK_PLUS )
+DEF_SDL_KEY( SDLK_COMMA )
+DEF_SDL_KEY( SDLK_MINUS )
+DEF_SDL_KEY( SDLK_PERIOD )
+DEF_SDL_KEY( SDLK_SLASH )
+DEF_SDL_KEY( SDLK_0 )
+DEF_SDL_KEY( SDLK_1 )
+DEF_SDL_KEY( SDLK_2 )
+DEF_SDL_KEY( SDLK_3 )
+DEF_SDL_KEY( SDLK_4 )
+DEF_SDL_KEY( SDLK_5 )
+DEF_SDL_KEY( SDLK_6 )
+DEF_SDL_KEY( SDLK_7 )
+DEF_SDL_KEY( SDLK_8 )
+DEF_SDL_KEY( SDLK_9 )
+DEF_SDL_KEY( SDLK_COLON )
+DEF_SDL_KEY( SDLK_SEMICOLON )
+DEF_SDL_KEY( SDLK_LESS )
+DEF_SDL_KEY( SDLK_EQUALS )
+DEF_SDL_KEY( SDLK_GREATER )
+DEF_SDL_KEY( SDLK_QUESTION )
+DEF_SDL_KEY( SDLK_AT )
+DEF_SDL_KEY( /*  )
+DEF_SDL_KEY( Skip uppercase letters )
+DEF_SDL_KEY( */ )
+DEF_SDL_KEY( SDLK_LEFTBRACKET )
+DEF_SDL_KEY( SDLK_BACKSLASH )
+DEF_SDL_KEY( SDLK_RIGHTBRACKET )
+DEF_SDL_KEY( SDLK_CARET )
+DEF_SDL_KEY( SDLK_UNDERSCORE )
+DEF_SDL_KEY( SDLK_BACKQUOTE )
+DEF_SDL_KEY( SDLK_a )
+DEF_SDL_KEY( SDLK_b )
+DEF_SDL_KEY( SDLK_c )
+DEF_SDL_KEY( SDLK_d )
+DEF_SDL_KEY( SDLK_e )
+DEF_SDL_KEY( SDLK_f )
+DEF_SDL_KEY( SDLK_g )
+DEF_SDL_KEY( SDLK_h )
+DEF_SDL_KEY( SDLK_i )
+DEF_SDL_KEY( SDLK_j )
+DEF_SDL_KEY( SDLK_k )
+DEF_SDL_KEY( SDLK_l )
+DEF_SDL_KEY( SDLK_m )
+DEF_SDL_KEY( SDLK_n )
+DEF_SDL_KEY( SDLK_o )
+DEF_SDL_KEY( SDLK_p )
+DEF_SDL_KEY( SDLK_q )
+DEF_SDL_KEY( SDLK_r )
+DEF_SDL_KEY( SDLK_s )
+DEF_SDL_KEY( SDLK_t )
+DEF_SDL_KEY( SDLK_u )
+DEF_SDL_KEY( SDLK_v )
+DEF_SDL_KEY( SDLK_w )
+DEF_SDL_KEY( SDLK_x )
+DEF_SDL_KEY( SDLK_y )
+DEF_SDL_KEY( SDLK_z )
+DEF_SDL_KEY( SDLK_DELETE )
+DEF_SDL_KEY( SDLK_WORLD_0 )
+DEF_SDL_KEY( SDLK_WORLD_1 )
+DEF_SDL_KEY( SDLK_WORLD_2 )
+DEF_SDL_KEY( SDLK_WORLD_3 )
+DEF_SDL_KEY( SDLK_WORLD_4 )
+DEF_SDL_KEY( SDLK_WORLD_5 )
+DEF_SDL_KEY( SDLK_WORLD_6 )
+DEF_SDL_KEY( SDLK_WORLD_7 )
+DEF_SDL_KEY( SDLK_WORLD_8 )
+DEF_SDL_KEY( SDLK_WORLD_9 )
+DEF_SDL_KEY( SDLK_WORLD_10 )
+DEF_SDL_KEY( SDLK_WORLD_11 )
+DEF_SDL_KEY( SDLK_WORLD_12 )
+DEF_SDL_KEY( SDLK_WORLD_13 )
+DEF_SDL_KEY( SDLK_WORLD_14 )
+DEF_SDL_KEY( SDLK_WORLD_15 )
+DEF_SDL_KEY( SDLK_WORLD_16 )
+DEF_SDL_KEY( SDLK_WORLD_17 )
+DEF_SDL_KEY( SDLK_WORLD_18 )
+DEF_SDL_KEY( SDLK_WORLD_19 )
+DEF_SDL_KEY( SDLK_WORLD_20 )
+DEF_SDL_KEY( SDLK_WORLD_21 )
+DEF_SDL_KEY( SDLK_WORLD_22 )
+DEF_SDL_KEY( SDLK_WORLD_23 )
+DEF_SDL_KEY( SDLK_WORLD_24 )
+DEF_SDL_KEY( SDLK_WORLD_25 )
+DEF_SDL_KEY( SDLK_WORLD_26 )
+DEF_SDL_KEY( SDLK_WORLD_27 )
+DEF_SDL_KEY( SDLK_WORLD_28 )
+DEF_SDL_KEY( SDLK_WORLD_29 )
+DEF_SDL_KEY( SDLK_WORLD_30 )
+DEF_SDL_KEY( SDLK_WORLD_31 )
+DEF_SDL_KEY( SDLK_WORLD_32 )
+DEF_SDL_KEY( SDLK_WORLD_33 )
+DEF_SDL_KEY( SDLK_WORLD_34 )
+DEF_SDL_KEY( SDLK_WORLD_35 )
+DEF_SDL_KEY( SDLK_WORLD_36 )
+DEF_SDL_KEY( SDLK_WORLD_37 )
+DEF_SDL_KEY( SDLK_WORLD_38 )
+DEF_SDL_KEY( SDLK_WORLD_39 )
+DEF_SDL_KEY( SDLK_WORLD_40 )
+DEF_SDL_KEY( SDLK_WORLD_41 )
+DEF_SDL_KEY( SDLK_WORLD_42 )
+DEF_SDL_KEY( SDLK_WORLD_43 )
+DEF_SDL_KEY( SDLK_WORLD_44 )
+DEF_SDL_KEY( SDLK_WORLD_45 )
+DEF_SDL_KEY( SDLK_WORLD_46 )
+DEF_SDL_KEY( SDLK_WORLD_47 )
+DEF_SDL_KEY( SDLK_WORLD_48 )
+DEF_SDL_KEY( SDLK_WORLD_49 )
+DEF_SDL_KEY( SDLK_WORLD_50 )
+DEF_SDL_KEY( SDLK_WORLD_51 )
+DEF_SDL_KEY( SDLK_WORLD_52 )
+DEF_SDL_KEY( SDLK_WORLD_53 )
+DEF_SDL_KEY( SDLK_WORLD_54 )
+DEF_SDL_KEY( SDLK_WORLD_55 )
+DEF_SDL_KEY( SDLK_WORLD_56 )
+DEF_SDL_KEY( SDLK_WORLD_57 )
+DEF_SDL_KEY( SDLK_WORLD_58 )
+DEF_SDL_KEY( SDLK_WORLD_59 )
+DEF_SDL_KEY( SDLK_WORLD_60 )
+DEF_SDL_KEY( SDLK_WORLD_61 )
+DEF_SDL_KEY( SDLK_WORLD_62 )
+DEF_SDL_KEY( SDLK_WORLD_63 )
+DEF_SDL_KEY( SDLK_WORLD_64 )
+DEF_SDL_KEY( SDLK_WORLD_65 )
+DEF_SDL_KEY( SDLK_WORLD_66 )
+DEF_SDL_KEY( SDLK_WORLD_67 )
+DEF_SDL_KEY( SDLK_WORLD_68 )
+DEF_SDL_KEY( SDLK_WORLD_69 )
+DEF_SDL_KEY( SDLK_WORLD_70 )
+DEF_SDL_KEY( SDLK_WORLD_71 )
+DEF_SDL_KEY( SDLK_WORLD_72 )
+DEF_SDL_KEY( SDLK_WORLD_73 )
+DEF_SDL_KEY( SDLK_WORLD_74 )
+DEF_SDL_KEY( SDLK_WORLD_75 )
+DEF_SDL_KEY( SDLK_WORLD_76 )
+DEF_SDL_KEY( SDLK_WORLD_77 )
+DEF_SDL_KEY( SDLK_WORLD_78 )
+DEF_SDL_KEY( SDLK_WORLD_79 )
+DEF_SDL_KEY( SDLK_WORLD_80 )
+DEF_SDL_KEY( SDLK_WORLD_81 )
+DEF_SDL_KEY( SDLK_WORLD_82 )
+DEF_SDL_KEY( SDLK_WORLD_83 )
+DEF_SDL_KEY( SDLK_WORLD_84 )
+DEF_SDL_KEY( SDLK_WORLD_85 )
+DEF_SDL_KEY( SDLK_WORLD_86 )
+DEF_SDL_KEY( SDLK_WORLD_87 )
+DEF_SDL_KEY( SDLK_WORLD_88 )
+DEF_SDL_KEY( SDLK_WORLD_89 )
+DEF_SDL_KEY( SDLK_WORLD_90 )
+DEF_SDL_KEY( SDLK_WORLD_91 )
+DEF_SDL_KEY( SDLK_WORLD_92 )
+DEF_SDL_KEY( SDLK_WORLD_93 )
+DEF_SDL_KEY( SDLK_WORLD_94 )
+DEF_SDL_KEY( SDLK_WORLD_95 )
+DEF_SDL_KEY( SDLK_KP0 )
+DEF_SDL_KEY( SDLK_KP1 )
+DEF_SDL_KEY( SDLK_KP2 )
+DEF_SDL_KEY( SDLK_KP3 )
+DEF_SDL_KEY( SDLK_KP4 )
+DEF_SDL_KEY( SDLK_KP5 )
+DEF_SDL_KEY( SDLK_KP6 )
+DEF_SDL_KEY( SDLK_KP7 )
+DEF_SDL_KEY( SDLK_KP8 )
+DEF_SDL_KEY( SDLK_KP9 )
+DEF_SDL_KEY( SDLK_KP_PERIOD )
+DEF_SDL_KEY( SDLK_KP_DIVIDE )
+DEF_SDL_KEY( SDLK_KP_MULTIPLY )
+DEF_SDL_KEY( SDLK_KP_MINUS )
+DEF_SDL_KEY( SDLK_KP_PLUS )
+DEF_SDL_KEY( SDLK_KP_ENTER )
+DEF_SDL_KEY( SDLK_KP_EQUALS )
+DEF_SDL_KEY( SDLK_UP )
+DEF_SDL_KEY( SDLK_DOWN )
+DEF_SDL_KEY( SDLK_RIGHT )
+DEF_SDL_KEY( SDLK_LEFT )
+DEF_SDL_KEY( SDLK_INSERT )
+DEF_SDL_KEY( SDLK_HOME )
+DEF_SDL_KEY( SDLK_END )
+DEF_SDL_KEY( SDLK_PAGEUP )
+DEF_SDL_KEY( SDLK_PAGEDOWN )
+DEF_SDL_KEY( SDLK_F1 )
+DEF_SDL_KEY( SDLK_F2 )
+DEF_SDL_KEY( SDLK_F3 )
+DEF_SDL_KEY( SDLK_F4 )
+DEF_SDL_KEY( SDLK_F5 )
+DEF_SDL_KEY( SDLK_F6 )
+DEF_SDL_KEY( SDLK_F7 )
+DEF_SDL_KEY( SDLK_F8 )
+DEF_SDL_KEY( SDLK_F9 )
+DEF_SDL_KEY( SDLK_F10 )
+DEF_SDL_KEY( SDLK_F11 )
+DEF_SDL_KEY( SDLK_F12 )
+DEF_SDL_KEY( SDLK_F13 )
+DEF_SDL_KEY( SDLK_F14 )
+DEF_SDL_KEY( SDLK_F15 )
+DEF_SDL_KEY( SDLK_NUMLOCK )
+DEF_SDL_KEY( SDLK_CAPSLOCK )
+DEF_SDL_KEY( SDLK_SCROLLOCK )
+DEF_SDL_KEY( SDLK_RSHIFT )
+DEF_SDL_KEY( SDLK_LSHIFT )
+DEF_SDL_KEY( SDLK_RCTRL )
+DEF_SDL_KEY( SDLK_LCTRL )
+DEF_SDL_KEY( SDLK_RALT )
+DEF_SDL_KEY( SDLK_LALT )
+DEF_SDL_KEY( SDLK_RMETA )
+DEF_SDL_KEY( SDLK_LMETA )
+DEF_SDL_KEY( SDLK_LSUPER )
+DEF_SDL_KEY( SDLK_RSUPER )
+DEF_SDL_KEY( SDLK_MODE )
+DEF_SDL_KEY( SDLK_COMPOSE )
+DEF_SDL_KEY( SDLK_HELP )
+DEF_SDL_KEY( SDLK_PRINT )
+DEF_SDL_KEY( SDLK_SYSREQ )
+DEF_SDL_KEY( SDLK_BREAK )
+DEF_SDL_KEY( SDLK_MENU )
+DEF_SDL_KEY( SDLK_POWER )
+DEF_SDL_KEY( SDLK_EURO )
+DEF_SDL_KEY( SDLK_UNDO )
diff --git a/tools/ioemu/gui/siminterface.cc b/tools/ioemu/gui/siminterface.cc
new file mode 100644 (file)
index 0000000..0284e6b
--- /dev/null
@@ -0,0 +1,1411 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: siminterface.cc,v 1.105 2004/01/05 22:18:01 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// See siminterface.h for description of the siminterface concept.
+// Basically, the siminterface is visible from both the simulator and
+// the configuration user interface, and allows them to talk to each other.
+
+#include "bochs.h"
+
+bx_simulator_interface_c *SIM = NULL;
+logfunctions *siminterface_log = NULL;
+#define LOG_THIS siminterface_log->
+
+// bx_simulator_interface just defines the interface that the Bochs simulator
+// and the gui will use to talk to each other.  None of the methods of
+// bx_simulator_interface are implemented; they are all virtual.  The
+// bx_real_sim_c class is a child of bx_simulator_interface_c, and it
+// implements all the methods.  The idea is that a gui needs to know only
+// definition of bx_simulator_interface to talk to Bochs.  The gui should
+// not need to include bochs.h.  
+//
+// I made this separation to ensure that all guis use the siminterface to do
+// access bochs internals, instead of accessing things like
+// bx_keyboard.s.internal_buffer[4] (or whatever) directly. -Bryce
+// 
+
+class bx_real_sim_c : public bx_simulator_interface_c {
+  bxevent_handler bxevent_callback;
+  void *bxevent_callback_data;
+  const char *registered_ci_name;
+  config_interface_callback_t ci_callback;
+  void *ci_callback_data;
+  int init_done;
+  bx_param_c **param_registry;
+  int registry_alloc_size;
+  int enabled;
+  // save context to jump to if we must quit unexpectedly
+  jmp_buf *quit_context;
+  int exit_code;
+public:
+  bx_real_sim_c ();
+  virtual ~bx_real_sim_c ();
+  virtual void set_quit_context (jmp_buf *context) { quit_context = context; }
+  virtual int get_init_done () { return init_done; }
+  virtual int set_init_done (int n) { init_done = n; return 0;}
+  virtual void get_param_id_range (int *min, int *max) {
+    *min = BXP_NULL;
+    *max = BXP_THIS_IS_THE_LAST-1;
+  }
+  virtual int register_param (bx_id id, bx_param_c *it);
+  virtual void reset_all_param ();
+  virtual bx_param_c *get_param (bx_id id);
+  virtual bx_param_num_c *get_param_num (bx_id id);
+  virtual bx_param_string_c *get_param_string (bx_id id);
+  virtual bx_param_bool_c *get_param_bool (bx_id id);
+  virtual bx_param_enum_c *get_param_enum (bx_id id);
+  virtual int get_n_log_modules ();
+  virtual char *get_prefix (int mod);
+  virtual int get_log_action (int mod, int level);
+  virtual void set_log_action (int mod, int level, int action);
+  virtual char *get_action_name (int action);
+  virtual int get_default_log_action (int level) {
+       return logfunctions::get_default_action (level);
+  }
+  virtual void set_default_log_action (int level, int action) {
+       logfunctions::set_default_action (level, action);
+  }
+  virtual const char *get_log_level_name (int level);
+  virtual int get_max_log_level ();
+  virtual void quit_sim (int code);
+  virtual int get_exit_code () { return exit_code; }
+  virtual int get_default_rc (char *path, int len);
+  virtual int read_rc (char *path);
+  virtual int write_rc (char *path, int overwrite);
+  virtual int get_log_file (char *path, int len);
+  virtual int set_log_file (char *path);
+  virtual int get_log_prefix (char *prefix, int len);
+  virtual int set_log_prefix (char *prefix);
+  virtual int get_debugger_log_file (char *path, int len);
+  virtual int set_debugger_log_file (char *path);
+  virtual int get_floppy_options (int drive, bx_floppy_options *out);
+  virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *device = NULL);
+  virtual char *get_floppy_type_name (int type);
+  virtual void set_notify_callback (bxevent_handler func, void *arg);
+  virtual void get_notify_callback (bxevent_handler *func, void **arg);
+  virtual BxEvent* sim_to_ci_event (BxEvent *event);
+  virtual int log_msg (const char *prefix, int level, const char *msg);
+  virtual int ask_param (bx_id which);
+  // ask the user for a pathname
+  virtual int ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags);
+  // called at a regular interval, currently by the keyboard handler.
+  virtual void periodic ();
+  virtual int create_disk_image (const char *filename, int sectors, bx_bool overwrite);
+  virtual void refresh_ci ();
+  virtual void refresh_vga () {
+    // maybe need to check if something has been initialized yet?
+    DEV_vga_refresh();
+  }
+  virtual void handle_events () {
+    // maybe need to check if something has been initialized yet?
+    bx_gui->handle_events ();
+  }
+  // find first hard drive or cdrom
+  bx_param_c *get_first_atadevice (Bit32u search_type);
+  bx_param_c *get_first_cdrom () {
+    return get_first_atadevice (BX_ATA_DEVICE_CDROM);
+  }
+  bx_param_c *get_first_hd () {
+    return get_first_atadevice (BX_ATA_DEVICE_DISK);
+  }
+#if BX_DEBUGGER
+  virtual void debug_break ();
+  virtual void debug_interpret_cmd (char *cmd);
+  virtual char *debug_get_next_command ();
+  virtual void debug_puts (const char *cmd);
+#endif
+  virtual void register_configuration_interface (
+    const char* name, 
+    config_interface_callback_t callback,
+    void *userdata);
+  virtual int configuration_interface(const char* name, ci_command_t command);
+  virtual int begin_simulation (int argc, char *argv[]);
+  virtual void set_sim_thread_func (is_sim_thread_func_t func) {}
+  virtual bool is_sim_thread ();
+  bool wxsel;
+  virtual bool is_wx_selected () { return wxsel; }
+  // provide interface to bx_gui->set_display_mode() method for config
+  // interfaces to use.
+  virtual void set_display_mode (disp_mode_t newmode) {
+    if (bx_gui != NULL)
+      bx_gui->set_display_mode (newmode);
+  }
+  virtual bool test_for_text_console ();
+};
+
+bx_param_c *
+bx_real_sim_c::get_param (bx_id id)
+{
+  BX_ASSERT (id >= BXP_NULL && id < BXP_THIS_IS_THE_LAST);
+  int index = (int)id - BXP_NULL;
+  bx_param_c *retval = param_registry[index];
+  if (!retval) 
+    BX_INFO (("get_param can't find id %u", id));
+  return retval;
+}
+
+bx_param_num_c *
+bx_real_sim_c::get_param_num (bx_id id) {
+  bx_param_c *generic = get_param(id);
+  if (generic==NULL) {
+    BX_PANIC (("get_param_num(%u) could not find a parameter", id));
+    return NULL;
+  }
+  int type = generic->get_type ();
+  if (type == BXT_PARAM_NUM || type == BXT_PARAM_BOOL || type == BXT_PARAM_ENUM)
+    return (bx_param_num_c *)generic;
+  BX_PANIC (("get_param_num %u could not find an integer parameter with that id", id));
+  return NULL;
+}
+
+bx_param_string_c *
+bx_real_sim_c::get_param_string (bx_id id) {
+  bx_param_c *generic = get_param(id);
+  if (generic==NULL) {
+    BX_PANIC (("get_param_string(%u) could not find a parameter", id));
+    return NULL;
+  }
+  if (generic->get_type () == BXT_PARAM_STRING)
+    return (bx_param_string_c *)generic;
+  BX_PANIC (("get_param_string %u could not find an integer parameter with that id", id));
+  return NULL;
+}
+
+bx_param_bool_c *
+bx_real_sim_c::get_param_bool (bx_id id) {
+  bx_param_c *generic = get_param(id);
+  if (generic==NULL) {
+    BX_PANIC (("get_param_bool(%u) could not find a parameter", id));
+    return NULL;
+  }
+  if (generic->get_type () == BXT_PARAM_BOOL)
+    return (bx_param_bool_c *)generic;
+  BX_PANIC (("get_param_bool %u could not find a bool parameter with that id", id));
+  return NULL;
+}
+
+bx_param_enum_c *
+bx_real_sim_c::get_param_enum (bx_id id) {
+  bx_param_c *generic = get_param(id);
+  if (generic==NULL) {
+    BX_PANIC (("get_param_enum(%u) could not find a parameter", id));
+    return NULL;
+  }
+  if (generic->get_type () == BXT_PARAM_ENUM)
+    return (bx_param_enum_c *)generic;
+  BX_PANIC (("get_param_enum %u could not find a enum parameter with that id", id));
+  return NULL;
+}
+
+void bx_init_siminterface ()
+{
+  siminterface_log = new logfunctions ();
+  siminterface_log->put ("CTRL");
+  siminterface_log->settype(CTRLLOG);
+  if (SIM == NULL) 
+    SIM = new bx_real_sim_c();
+}
+
+bx_simulator_interface_c::bx_simulator_interface_c ()
+{
+}
+
+bx_real_sim_c::bx_real_sim_c ()
+{
+  bxevent_callback = NULL;
+  bxevent_callback_data = NULL;
+  ci_callback = NULL;
+  ci_callback_data = NULL;
+  is_sim_thread_func = NULL;
+  wxsel = false;
+  
+  enabled = 1;
+  int i;
+  init_done = 0;
+  registry_alloc_size = BXP_THIS_IS_THE_LAST - BXP_NULL;
+  param_registry = new bx_param_c*  [registry_alloc_size];
+  for (i=0; i<registry_alloc_size; i++)
+    param_registry[i] = NULL;
+  quit_context = NULL;
+  exit_code = 0;
+}
+
+// called by constructor of bx_param_c, so that every parameter that is
+// initialized gets registered.  This builds a list of all parameters
+// which can be used to look them up by number (get_param).
+bx_real_sim_c::~bx_real_sim_c ()
+{
+    if ( param_registry != NULL )
+    {
+        delete [] param_registry;
+        param_registry = NULL;
+    }
+}
+
+int
+bx_real_sim_c::register_param (bx_id id, bx_param_c *it)
+{
+  if (id == BXP_NULL) return 0;
+  BX_ASSERT (id >= BXP_NULL && id < BXP_THIS_IS_THE_LAST);
+  int index = (int)id - BXP_NULL;
+  if (this->param_registry[index] != NULL) {
+    BX_INFO (("register_param is overwriting parameter id %d", id));
+  }
+  this->param_registry[index] = it;
+  return 0;
+}
+
+void 
+bx_real_sim_c::reset_all_param ()
+{
+  bx_reset_options ();
+}
+
+int 
+bx_real_sim_c::get_n_log_modules ()
+{
+  return io->get_n_logfns ();
+}
+
+char *
+bx_real_sim_c::get_prefix (int mod)
+{
+  logfunc_t *logfn = io->get_logfn (mod);
+  return logfn->getprefix ();
+}
+
+int 
+bx_real_sim_c::get_log_action (int mod, int level)
+{
+  logfunc_t *logfn = io->get_logfn (mod);
+  return logfn->getonoff (level);
+}
+
+void 
+bx_real_sim_c::set_log_action (int mod, int level, int action)
+{
+  // normal
+  if (mod >= 0) {
+       logfunc_t *logfn = io->get_logfn (mod);
+       logfn->setonoff (level, action);
+       return;
+  }
+  // if called with mod<0 loop over all
+  int nmod = get_n_log_modules ();
+  for (mod=0; mod<nmod; mod++)
+       set_log_action (mod, level, action);
+}
+
+char *
+bx_real_sim_c::get_action_name (int action)
+{
+  return io->getaction (action);
+}
+
+const char *
+bx_real_sim_c::get_log_level_name (int level)
+{
+  return io->getlevel (level);
+}
+
+int 
+bx_real_sim_c::get_max_log_level ()
+{
+  return N_LOGLEV;
+}
+
+void 
+bx_real_sim_c::quit_sim (int code) {
+  BX_INFO (("quit_sim called with exit code %d", code));
+  exit_code = code;
+  // use longjmp to quit cleanly, no matter where in the stack we are.
+  //fprintf (stderr, "using longjmp() to jump directly to the quit context!\n");
+  if (quit_context != NULL) {
+    longjmp (*quit_context, 1);
+    BX_PANIC (("in bx_real_sim_c::quit_sim, longjmp should never return"));
+  }
+  if (SIM->is_wx_selected ()) {
+    // in wxWindows, the whole simulator is running in a separate thread.
+    // our only job is to end the thread as soon as possible, NOT to shut
+    // down the whole application with an exit.
+    BX_CPU(0)->async_event = 1;
+    BX_CPU(0)->kill_bochs_request = 1;
+    // the cpu loop will exit very soon after this condition is set.
+  } else {
+    // just a single thread.  Use exit() to stop the application.
+    if (!code)
+      BX_PANIC (("Quit simulation command"));
+    ::exit (exit_code);
+  }
+}
+
+int
+bx_real_sim_c::get_default_rc (char *path, int len)
+{
+  char *rc = bx_find_bochsrc ();
+  if (rc == NULL) return -1;
+  strncpy (path, rc, len);
+  path[len-1] = 0;
+  return 0;
+}
+
+int 
+bx_real_sim_c::read_rc (char *rc)
+{
+  return bx_read_configuration (rc);
+}
+
+// return values:
+//   0: written ok
+//  -1: failed
+//  -2: already exists, and overwrite was off
+int 
+bx_real_sim_c::write_rc (char *rc, int overwrite)
+{
+  return bx_write_configuration (rc, overwrite);
+}
+
+int 
+bx_real_sim_c::get_log_file (char *path, int len)
+{
+  strncpy (path, bx_options.log.Ofilename->getptr (), len);
+  return 0;
+}
+
+int 
+bx_real_sim_c::set_log_file (char *path)
+{
+  bx_options.log.Ofilename->set (path);
+  return 0;
+}
+
+int 
+bx_real_sim_c::get_log_prefix (char *prefix, int len)
+{
+  strncpy (prefix, bx_options.log.Oprefix->getptr (), len);
+  return 0;
+}
+
+int 
+bx_real_sim_c::set_log_prefix (char *prefix)
+{
+  bx_options.log.Oprefix->set (prefix);
+  return 0;
+}
+
+int 
+bx_real_sim_c::get_debugger_log_file (char *path, int len)
+{
+  strncpy (path, bx_options.log.Odebugger_filename->getptr (), len);
+  return 0;
+}
+
+int 
+bx_real_sim_c::set_debugger_log_file (char *path)
+{
+  bx_options.log.Odebugger_filename->set (path);
+  return 0;
+}
+
+int 
+bx_real_sim_c::get_floppy_options (int drive, bx_floppy_options *out)
+{
+  *out = (drive==0)? bx_options.floppya : bx_options.floppyb;
+  return 0;
+}
+
+int 
+bx_real_sim_c::get_cdrom_options (int level, bx_atadevice_options *out, int *where)
+{
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    for (Bit8u device=0; device<2; device++) {
+      if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_CDROM) {
+        if (level==0) {
+          *out = bx_options.atadevice[channel][device];
+         if (where != NULL) *where=(channel*2)+device;
+          return 1;
+          }
+        else level--;
+       }
+      }
+    }
+  return 0;
+}
+
+char *bochs_start_names[] = { "quick", "load", "edit", "run" };
+int n_bochs_start_names = 3;
+
+char *floppy_type_names[] = { "none", "1.2M", "1.44M", "2.88M", "720K", "360K", "160K", "180K", "320K", NULL };
+int floppy_type_n_sectors[] = { -1, 80*2*15, 80*2*18, 80*2*36, 80*2*9, 40*2*9, 40*1*8, 40*1*9, 40*2*8 };
+int n_floppy_type_names = 9;
+
+char *floppy_status_names[] = { "ejected", "inserted", NULL };
+int n_floppy_status_names = 2;
+char *floppy_bootdisk_names[] = { "floppy", "disk","cdrom", NULL };
+int n_floppy_bootdisk_names = 3;
+char *loader_os_names[] = { "none", "linux", "nullkernel", NULL };
+int n_loader_os_names = 3;
+char *keyboard_type_names[] = { "xt", "at", "mf", NULL };
+int n_keyboard_type_names = 3;
+
+char *atadevice_type_names[] = { "disk", "cdrom", NULL };
+int n_atadevice_type_names = 2;
+//char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "split", "undoable", "growing", "volatile", "z-undoable", "z-volatile", NULL };
+char *atadevice_mode_names[] = { "flat", "concat", "external", "dll", "sparse", "vmware3", "undoable", "growing", "volatile", NULL };
+int n_atadevice_mode_names = 9;
+char *atadevice_status_names[] = { "ejected", "inserted", NULL };
+int n_atadevice_status_names = 2;
+char *atadevice_biosdetect_names[] = { "none", "auto", "cmos", NULL };
+int n_atadevice_biosdetect_names = 3;
+char *atadevice_translation_names[] = { "none", "lba", "large", "rechs", "auto", NULL };
+int n_atadevice_translation_names = 5;
+char *clock_sync_names[] = { "none", "realtime", "slowdown", "both", NULL };
+int clock_sync_n_names=4;
+
+
+
+char *
+bx_real_sim_c::get_floppy_type_name (int type)
+{
+  BX_ASSERT (type >= BX_FLOPPY_NONE && type <= BX_FLOPPY_LAST);
+  type -= BX_FLOPPY_NONE;
+  return floppy_type_names[type];
+}
+
+void 
+bx_real_sim_c::set_notify_callback (bxevent_handler func, void *arg)
+{
+  bxevent_callback = func;
+  bxevent_callback_data = arg;
+}
+
+void bx_real_sim_c::get_notify_callback (
+    bxevent_handler *func,
+    void **arg)
+{
+  *func = bxevent_callback;
+  *arg = bxevent_callback_data;
+}
+
+BxEvent *
+bx_real_sim_c::sim_to_ci_event (BxEvent *event)
+{
+  if (bxevent_callback == NULL) {
+    BX_ERROR (("notify called, but no bxevent_callback function is registered"));
+    return NULL;
+  } else {
+    return (*bxevent_callback)(bxevent_callback_data, event);
+  }
+}
+
+// returns 0 for continue, 1 for alwayscontinue, 2 for die.
+int 
+bx_real_sim_c::log_msg (const char *prefix, int level, const char *msg)
+{
+  BxEvent be;
+  be.type = BX_SYNC_EVT_LOG_ASK;
+  be.u.logmsg.prefix = prefix;
+  be.u.logmsg.level = level;
+  be.u.logmsg.msg = msg;
+  // default return value in case something goes wrong.
+  be.retcode = BX_LOG_ASK_CHOICE_DIE;
+  //fprintf (stderr, "calling notify.\n");
+  sim_to_ci_event (&be);
+  return be.retcode;
+}
+
+// Called by simulator whenever it needs the user to choose a new value
+// for a registered parameter.  Create a synchronous ASK_PARAM event, 
+// send it to the CI, and wait for the response.  The CI will call the
+// set() method on the parameter if the user changes the value.
+int 
+bx_real_sim_c::ask_param (bx_id param)
+{
+  bx_param_c *paramptr = SIM->get_param(param);
+  BX_ASSERT (paramptr != NULL);
+  // create appropriate event
+  BxEvent event;
+  event.type = BX_SYNC_EVT_ASK_PARAM;
+  event.u.param.param = paramptr;
+  sim_to_ci_event (&event);
+  return event.retcode;
+}
+
+int
+bx_real_sim_c::ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags)
+{
+  // implement using ASK_PARAM on a newly created param.  I can't use
+  // ask_param because I don't intend to register this param.
+  BxEvent event;
+  bx_param_string_c param (BXP_NULL, prompt, "filename", the_default, maxlen);
+  flags |= param.IS_FILENAME;
+  param.get_options()->set (flags);
+  event.type = BX_SYNC_EVT_ASK_PARAM;
+  event.u.param.param = &param;
+  sim_to_ci_event (&event);
+  if (event.retcode >= 0)
+    memcpy (filename, param.getptr(), maxlen);
+  return event.retcode;
+}
+
+void
+bx_real_sim_c::periodic ()
+{
+  // give the GUI a chance to do periodic things on the bochs thread. in 
+  // particular, notice if the thread has been asked to die.
+  BxEvent tick;
+  tick.type = BX_SYNC_EVT_TICK;
+  sim_to_ci_event (&tick);
+  if (tick.retcode < 0) {
+    BX_INFO (("Bochs thread has been asked to quit."));
+    bx_atexit ();
+    quit_sim (0);
+  }
+  static int refresh_counter = 0;
+  if (++refresh_counter == 50) {
+    // only ask the CI to refresh every 50 times periodic() is called.
+    // This should obviously be configurable because system speeds and
+    // user preferences vary.
+    refresh_ci ();
+    refresh_counter = 0;
+  }
+#if 0
+  // watch for memory leaks.  Allocate a small block of memory, print the
+  // pointer that is returned, then free.
+  BxEvent *memcheck = new BxEvent ();
+  BX_INFO(("memory allocation at %p", memcheck));
+  delete memcheck;
+#endif
+}
+
+// create a disk image file called filename, size=512 bytes * sectors.
+// If overwrite is true and the file exists, returns -1 without changing it.
+// Otherwise, opens up the image and starts writing.  Returns -2 if
+// the image could not be opened, or -3 if there are failures during
+// write, e.g. disk full.
+// 
+// wxWindows: This may be called from the gui thread.
+int 
+bx_real_sim_c::create_disk_image (
+    const char *filename,
+    int sectors,
+    bx_bool overwrite) 
+{
+  FILE *fp;
+  if (!overwrite) {
+    // check for existence first
+    fp = fopen (filename, "r");
+    if (fp) {
+      // yes it exists
+      fclose (fp);
+      return -1;
+    }
+  }
+  fp = fopen (filename, "w");
+  if (fp == NULL) {
+#ifdef HAVE_PERROR
+    char buffer[1024];
+    sprintf (buffer, "while opening '%s' for writing", filename);
+    perror (buffer);
+    // not sure how to get this back into the CI
+#endif
+    return -2;
+  }
+  int sec = sectors;
+  /*
+   * seek to sec*512-1 and write a single character.
+   * can't just do: fseek(fp, 512*sec-1, SEEK_SET)
+   * because 512*sec may be too large for signed int.
+   */
+  while (sec > 0)
+  {
+    /* temp <-- min(sec, 4194303)
+     * 4194303 is (int)(0x7FFFFFFF/512)
+     */
+    int temp = ((sec < 4194303) ? sec : 4194303);
+    fseek(fp, 512*temp, SEEK_CUR);
+    sec -= temp;
+  }
+
+  fseek(fp, -1, SEEK_CUR);
+  if (fputc('\0', fp) == EOF)
+  {
+    fclose (fp);
+    return -3;
+  }
+  fclose (fp);
+  return 0;
+}
+
+void bx_real_sim_c::refresh_ci () {
+  if (SIM->is_wx_selected ()) {
+    // presently, only wxWindows interface uses these events
+    // It's an async event, so allocate a pointer and send it.
+    // The event will be freed by the recipient.
+    BxEvent *event = new BxEvent ();
+    event->type = BX_ASYNC_EVT_REFRESH;
+    sim_to_ci_event (event);
+  }
+}
+
+bx_param_c *
+bx_real_sim_c::get_first_atadevice (Bit32u search_type) {
+  for (int channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if (!bx_options.ata[channel].Opresent->get ())
+      continue;
+    for (int slave=0; slave<2; slave++) {
+      Bit32u present = bx_options.atadevice[channel][slave].Opresent->get ();
+      Bit32u type = bx_options.atadevice[channel][slave].Otype->get ();
+      if (present && (type == search_type)) {
+       return bx_options.atadevice[channel][slave].Omenu;
+      }
+    }
+  }
+  return NULL;
+}
+
+#if BX_DEBUGGER
+
+// this can be safely called from either thread.
+void bx_real_sim_c::debug_break () {
+  bx_debug_break ();
+}
+
+// this should only be called from the sim_thread.
+void bx_real_sim_c::debug_interpret_cmd (char *cmd) {
+  if (!is_sim_thread ()) {
+    fprintf (stderr, "ERROR: debug_interpret_cmd called but not from sim_thread\n");
+    return;
+  }
+  bx_dbg_interpret_line (cmd);
+}
+
+char *bx_real_sim_c::debug_get_next_command ()
+{
+  fprintf (stderr, "begin debug_get_next_command\n");
+  BxEvent event;
+  event.type = BX_SYNC_EVT_GET_DBG_COMMAND;
+  BX_INFO (("asking for next debug command"));
+  sim_to_ci_event (&event);
+  BX_INFO (("received next debug command: '%s'", event.u.debugcmd.command));
+  if (event.retcode >= 0)
+    return event.u.debugcmd.command;
+  return NULL;
+}
+
+void bx_real_sim_c::debug_puts (const char *text)
+{
+  if (SIM->is_wx_selected ()) {
+    // send message to the wxWindows debugger
+    BxEvent *event = new BxEvent ();
+    event->type = BX_ASYNC_EVT_DBG_MSG;
+    event->u.logmsg.msg = text;
+    sim_to_ci_event (event);
+    // the event will be freed by the recipient
+  } else {
+    // text mode debugger: just write to console
+    fputs (text, stderr);
+    delete [] (char *)text;
+  }
+}
+#endif
+
+void 
+bx_real_sim_c::register_configuration_interface (
+  const char* name, 
+  config_interface_callback_t callback,
+  void *userdata)
+{
+  ci_callback = callback;
+  ci_callback_data = userdata;
+  registered_ci_name = name;
+}
+
+int 
+bx_real_sim_c::configuration_interface(const char *ignore, ci_command_t command)
+{
+  bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+  char *name = ci_param->get_choice (ci_param->get ());
+  if (!ci_callback) {
+    BX_PANIC (("no configuration interface was loaded"));
+    return -1;
+  }
+  if (strcmp (name, registered_ci_name) != 0) {
+    BX_PANIC (("siminterface does not support loading one configuration interface and then calling another"));
+    return -1;
+  }
+  if (!strcmp (name, "wx")) 
+    wxsel = true;
+  else
+    wxsel = false;
+  // enter configuration mode, just while running the configuration interface
+  set_display_mode (DISP_MODE_CONFIG);
+  int retval = (*ci_callback)(ci_callback_data, command);
+  set_display_mode (DISP_MODE_SIM);
+  return retval;
+}
+
+int 
+bx_real_sim_c::begin_simulation (int argc, char *argv[])
+{
+  return bx_begin_simulation (argc, argv);
+}
+
+bool bx_real_sim_c::is_sim_thread ()
+{
+  if (is_sim_thread_func == NULL) return true;
+  return (*is_sim_thread_func)();
+}
+
+// check if the text console exists.  On some platforms, if Bochs is
+// started from the "Start Menu" or by double clicking on it on a Mac,
+// there may be nothing attached to stdin/stdout/stderr.  This function
+// tests if stdin/stdout/stderr are usable and returns false if not.
+bool 
+bx_real_sim_c::test_for_text_console ()
+{
+#if BX_WITH_CARBON
+  // In a Carbon application, you have a text console if you run the app from
+  // the command line, but if you start it from the finder you don't.
+  if(!isatty(STDIN_FILENO)) return false;
+#endif
+  // default: yes
+  return true;
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// define methods of bx_param_* and family
+/////////////////////////////////////////////////////////////////////////
+
+bx_object_c::bx_object_c (bx_id id)
+{
+  this->id = id;
+  this->type = BXT_OBJECT;
+}
+
+void
+bx_object_c::set_type (bx_objtype type)
+{
+  this->type = type;
+}
+
+const char* bx_param_c::default_text_format = NULL;
+
+bx_param_c::bx_param_c (bx_id id, char *name, char *description)
+  : bx_object_c (id)
+{
+  set_type (BXT_PARAM);
+  this->name = name;
+  this->description = description;
+  this->text_format = default_text_format;
+  this->ask_format = NULL;
+  this->label = NULL;
+  this->runtime_param = 0;
+  this->enabled = 1;
+  SIM->register_param (id, this);
+}
+
+const char* bx_param_c::set_default_format (const char *f) {
+  const char *old = default_text_format;
+  default_text_format = f; 
+  return old;
+}
+
+bx_param_num_c::bx_param_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit64s min, Bit64s max, Bit64s initial_val)
+  : bx_param_c (id, name, description)
+{
+  set_type (BXT_PARAM_NUM);
+  this->min = min;
+  this->max = max;
+  this->initial_val = initial_val;
+  this->val.number = initial_val;
+  this->handler = NULL;
+  this->enable_handler = NULL;
+  this->base = default_base;
+  // dependent_list must be initialized before the set(),
+  // because set calls update_dependents().
+  dependent_list = NULL;
+  set (initial_val);
+}
+
+Bit32u bx_param_num_c::default_base = 10;
+
+Bit32u bx_param_num_c::set_default_base (Bit32u val) {
+  Bit32u old = default_base;
+  default_base = val; 
+  return old;
+}
+
+void 
+bx_param_num_c::reset ()
+{
+  this->val.number = initial_val;
+}
+
+void 
+bx_param_num_c::set_handler (param_event_handler handler)
+{ 
+  this->handler = handler; 
+  // now that there's a handler, call set once to run the handler immediately
+  //set (get ());
+}
+
+void 
+bx_param_num_c::set_enable_handler (param_enable_handler handler)
+{ 
+  this->enable_handler = handler; 
+}
+
+void bx_param_num_c::set_dependent_list (bx_list_c *l) {
+  dependent_list = l; 
+  update_dependents ();
+}
+
+Bit64s 
+bx_param_num_c::get64 ()
+{
+  if (handler) {
+    // the handler can decide what value to return and/or do some side effect
+    return (*handler)(this, 0, val.number);
+  } else {
+    // just return the value
+    return val.number;
+  }
+}
+
+void
+bx_param_num_c::set (Bit64s newval)
+{
+  if (handler) {
+    // the handler can override the new value and/or perform some side effect
+    val.number = newval;
+    (*handler)(this, 1, newval);
+  } else {
+    // just set the value.  This code does not check max/min.
+    val.number = newval;
+  }
+  if ((val.number < min || val.number > max) && (Bit64u)max != BX_MAX_BIT64U)
+    BX_PANIC (("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), val.number, min, max));
+  if (dependent_list != NULL) update_dependents ();
+}
+
+void bx_param_num_c::set_range (Bit64u min, Bit64u max)
+{
+  this->min = min;
+  this->max = max;
+}
+
+void bx_param_num_c::set_initial_val (Bit64s initial_val) { 
+  this->val.number = this->initial_val = initial_val;
+}
+
+void bx_param_num_c::update_dependents ()
+{
+  if (dependent_list) {
+    int en = val.number && enabled;
+    for (int i=0; i<dependent_list->get_size (); i++) {
+      bx_param_c *param = dependent_list->get (i);
+      if (param != this)
+       param->set_enabled (en);
+    }
+  }
+}
+
+void
+bx_param_num_c::set_enabled (int en)
+{
+  // The enable handler may wish to allow/disallow the action
+  if (enable_handler) {
+    en = (*enable_handler) (this, en);
+    }
+  bx_param_c::set_enabled (en);
+  update_dependents ();
+}
+
+// Signed 64 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit64s *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT64S, BX_MAX_BIT64S, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p64bit = ptr_to_real_val;
+}
+
+// Unsigned 64 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit64u *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT64U, BX_MAX_BIT64U, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p64bit = (Bit64s*) ptr_to_real_val;
+}
+
+// Signed 32 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit32s *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT32S, BX_MAX_BIT32S, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p32bit = ptr_to_real_val;
+}
+
+// Unsigned 32 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit32u *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT32U, BX_MAX_BIT32U, *ptr_to_real_val)
+{
+  this->varsize = 32;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p32bit = (Bit32s*) ptr_to_real_val;
+}
+
+// Signed 16 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit16s *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT16S, BX_MAX_BIT16S, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p16bit = ptr_to_real_val;
+}
+
+// Unsigned 16 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit16u *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT16U, BX_MAX_BIT16U, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p16bit = (Bit16s*) ptr_to_real_val;
+}
+
+// Signed 8 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit8s *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT8S, BX_MAX_BIT8S, *ptr_to_real_val)
+{
+  this->varsize = 16;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p8bit = ptr_to_real_val;
+}
+
+// Unsigned 8 bit
+bx_shadow_num_c::bx_shadow_num_c (bx_id id,
+    char *name,
+    char *description,
+    Bit8u *ptr_to_real_val,
+    Bit8u highbit,
+    Bit8u lowbit)
+: bx_param_num_c (id, name, description, BX_MIN_BIT8U, BX_MAX_BIT8U, *ptr_to_real_val)
+{
+  this->varsize = 8;
+  this->lowbit = lowbit;
+  this->mask = (1 << (highbit - lowbit)) - 1;
+  val.p8bit = (Bit8s*) ptr_to_real_val;
+}
+
+Bit64s
+bx_shadow_num_c::get64 () {
+  Bit64u current = 0;
+  switch (varsize) {
+    case 8: current = *(val.p8bit);  break;
+    case 16: current = *(val.p16bit);  break;
+    case 32: current = *(val.p32bit);  break;
+    case 64: current = *(val.p64bit);  break;
+    default: BX_PANIC(("unsupported varsize %d", varsize));
+  }
+  current = (current >> lowbit) & mask;
+  if (handler) {
+    // the handler can decide what value to return and/or do some side effect
+    return (*handler)(this, 0, current) & mask;
+  } else {
+    // just return the value
+    return current;
+  }
+}
+
+void
+bx_shadow_num_c::set (Bit64s newval)
+{
+  Bit64u tmp = 0;
+  if ((newval < min || newval > max) && (Bit64u)max != BX_MAX_BIT64U)
+    BX_PANIC (("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), newval, min, max));
+  switch (varsize) {
+    case 8: 
+      tmp = (*(val.p8bit) >> lowbit) & mask;
+      tmp |= (newval & mask) << lowbit;
+      *(val.p8bit) = (Bit8s)tmp;
+      break;
+    case 16:
+      tmp = (*(val.p16bit) >> lowbit) & mask;
+      tmp |= (newval & mask) << lowbit;
+      *(val.p16bit) = (Bit16s)tmp;
+      break;
+    case 32:
+      tmp = (*(val.p32bit) >> lowbit) & mask;
+      tmp |= (newval & mask) << lowbit;
+      *(val.p32bit) = (Bit32s)tmp;
+      break;
+    case 64:
+      tmp = (*(val.p64bit) >> lowbit) & mask;
+      tmp |= (newval & mask) << lowbit;
+      *(val.p64bit) = tmp;
+      break;
+    default: 
+      BX_PANIC(("unsupported varsize %d", varsize));
+  }
+  if (handler) {
+    // the handler can override the new value and/or perform some side effect
+    (*handler)(this, 1, tmp);
+  }
+}
+
+bx_param_bool_c::bx_param_bool_c (bx_id id,
+    char *name,
+    char *description,
+    Bit64s initial_val)
+  : bx_param_num_c (id, name, description, 0, 1, initial_val)
+{
+  set_type (BXT_PARAM_BOOL);
+  set (initial_val);
+}
+
+bx_shadow_bool_c::bx_shadow_bool_c (bx_id id,
+      char *name,
+      char *description,
+      bx_bool *ptr_to_real_val,
+      Bit8u bitnum)
+  : bx_param_bool_c (id, name, description, (Bit64s) *ptr_to_real_val)
+{
+  val.pbool = ptr_to_real_val;
+  this->bitnum = bitnum;
+}
+
+Bit64s
+bx_shadow_bool_c::get64 () {
+  if (handler) {
+    // the handler can decide what value to return and/or do some side effect
+    Bit64s ret = (*handler)(this, 0, (Bit64s) *(val.pbool));
+    return (ret>>bitnum) & 1;
+  } else {
+    // just return the value
+    return (*(val.pbool)) & 1;
+  }
+}
+
+void
+bx_shadow_bool_c::set (Bit64s newval)
+{
+  // only change the bitnum bit
+  Bit64s tmp = (newval&1) << bitnum;
+  *(val.pbool) &= ~tmp;
+  *(val.pbool) |= tmp;
+  if (handler) {
+    // the handler can override the new value and/or perform some side effect
+    (*handler)(this, 1, newval&1);
+  }
+}
+
+bx_param_enum_c::bx_param_enum_c (bx_id id, 
+      char *name,
+      char *description,
+      char **choices,
+      Bit64s initial_val,
+      Bit64s value_base)
+  : bx_param_num_c (id, name, description, value_base, BX_MAX_BIT64S, initial_val)
+{
+  set_type (BXT_PARAM_ENUM);
+  this->choices = choices;
+  // count number of choices, set max
+  char **p = choices;
+  while (*p != NULL) p++;
+  this->min = value_base;
+  // now that the max is known, replace the BX_MAX_BIT64S sent to the parent
+  // class constructor with the real max.
+  this->max = value_base + (p - choices - 1);
+  set (initial_val);
+}
+
+int 
+bx_param_enum_c::find_by_name (const char *string)
+{
+  char **p;
+  for (p=&choices[0]; *p; p++) {
+    if (!strcmp (string, *p))
+      return p-choices;
+  }
+  return -1;
+}
+
+bool 
+bx_param_enum_c::set_by_name (const char *string)
+{
+  int n = find_by_name (string);
+  if (n<0) return false;
+  set (n);
+  return true;
+}
+
+bx_param_string_c::bx_param_string_c (bx_id id,
+    char *name,
+    char *description,
+    char *initial_val,
+    int maxsize)
+  : bx_param_c (id, name, description)
+{
+  set_type (BXT_PARAM_STRING);
+  if (maxsize < 0) 
+    maxsize = strlen(initial_val) + 1;
+  this->val = new char[maxsize];
+  this->initial_val = new char[maxsize];
+  this->handler = NULL;
+  this->enable_handler = NULL;
+  this->maxsize = maxsize;
+  strncpy (this->val, initial_val, maxsize);
+  strncpy (this->initial_val, initial_val, maxsize);
+  this->options = new bx_param_num_c (BXP_NULL,
+      "stringoptions", NULL, 0, BX_MAX_BIT64S, 0);
+  set (initial_val);
+}
+
+bx_param_filename_c::bx_param_filename_c (bx_id id,
+    char *name,
+    char *description,
+    char *initial_val,
+    int maxsize)
+  : bx_param_string_c (id, name, description, initial_val, maxsize)
+{
+  get_options()->set (IS_FILENAME);
+}
+
+bx_param_string_c::~bx_param_string_c ()
+{
+    if ( this->val != NULL )
+    {
+        delete [] this->val;
+        this->val = NULL;
+    }
+    if ( this->initial_val != NULL )
+    {
+        delete [] this->initial_val;
+        this->initial_val = NULL;
+    }
+
+    if ( this->options != NULL )
+    {
+        delete [] this->options;
+        this->options = NULL;
+    }
+}
+
+void 
+bx_param_string_c::reset () {
+  strncpy (this->val, this->initial_val, maxsize);
+}
+
+void 
+bx_param_string_c::set_handler (param_string_event_handler handler)
+{
+  this->handler = handler; 
+  // now that there's a handler, call set once to run the handler immediately
+  //set (getptr ());
+}
+
+void 
+bx_param_string_c::set_enable_handler (param_enable_handler handler)
+{ 
+  this->enable_handler = handler; 
+}
+
+void
+bx_param_string_c::set_enabled (int en)
+{
+  // The enable handler may wish to allow/disallow the action
+  if (enable_handler) {
+    en = (*enable_handler) (this, en);
+    }
+  bx_param_c::set_enabled (en);
+}
+
+Bit32s
+bx_param_string_c::get (char *buf, int len)
+{
+  if (options->get () & RAW_BYTES)
+    memcpy (buf, val, len);
+  else
+    strncpy (buf, val, len);
+  if (handler) {
+    // the handler can choose to replace the value in val/len.  Also its
+    // return value is passed back as the return value of get.
+    (*handler)(this, 0, buf, len);
+  }
+  return 0;
+}
+
+void 
+bx_param_string_c::set (char *buf)
+{
+  if (options->get () & RAW_BYTES)
+    memcpy (val, buf, maxsize);
+  else
+    strncpy (val, buf, maxsize);
+  if (handler) {
+    // the handler can return a different char* to be copied into the value
+    buf = (*handler)(this, 1, buf, -1);
+  }
+}
+
+bx_bool
+bx_param_string_c::equals (const char *buf)
+{
+  if (options->get () & RAW_BYTES)
+    return (memcmp (val, buf, maxsize) == 0);
+  else
+    return (strncmp (val, buf, maxsize) == 0);
+}
+
+bx_list_c::bx_list_c (bx_id id, int maxsize)
+  : bx_param_c (id, "list", "")
+{
+  set_type (BXT_LIST);
+  this->size = 0;
+  this->maxsize = maxsize;
+  this->list = new bx_param_c*  [maxsize];
+  init ();
+}
+
+bx_list_c::bx_list_c (bx_id id, char *name, char *description, int maxsize)
+  : bx_param_c (id, name, description)
+{
+  set_type (BXT_LIST);
+  this->size = 0;
+  this->maxsize = maxsize;
+  this->list = new bx_param_c*  [maxsize];
+  init ();
+}
+
+bx_list_c::bx_list_c (bx_id id, char *name, char *description, bx_param_c **init_list)
+  : bx_param_c (id, name, description)
+{
+  set_type (BXT_LIST);
+  this->size = 0;
+  while (init_list[this->size] != NULL)
+    this->size++;
+  this->maxsize = this->size;
+  this->list = new bx_param_c*  [maxsize];
+  for (int i=0; i<this->size; i++)
+    this->list[i] = init_list[i];
+  init ();
+}
+
+bx_list_c::~bx_list_c()
+{
+    if (this->list)
+    {
+        delete [] this->list;
+        this->list = NULL;
+    }
+    if ( this->title != NULL)
+    {
+        delete this->title;
+        this->title = NULL;
+    }
+    if (this->options != NULL)
+    {
+        delete this->options;
+        this->options = NULL;
+    }
+    if ( this->choice != NULL )
+    {
+        delete this->choice;
+        this->choice = NULL;
+    }
+}
+
+void
+bx_list_c::init ()
+{
+  // the title defaults to the name
+  this->title = new bx_param_string_c (BXP_NULL,
+      "title of list",
+      "",
+      get_name (), 80);
+  this->options = new bx_param_num_c (BXP_NULL,
+      "list_option", "", 0, BX_MAX_BIT64S,
+      0);
+  this->choice = new bx_param_num_c (BXP_NULL,
+      "list_choice", "", 0, BX_MAX_BIT64S,
+      1);
+  this->parent = NULL;
+}
+
+bx_list_c *
+bx_list_c::clone ()
+{
+  bx_list_c *newlist = new bx_list_c (BXP_NULL, name, description, maxsize);
+  for (int i=0; i<get_size (); i++)
+    newlist->add (get(i));
+  newlist->set_options (get_options ());
+  newlist->set_parent (get_parent ());
+  return newlist;
+}
+
+void
+bx_list_c::add (bx_param_c *param)
+{
+  if (this->size >= this->maxsize)
+    BX_PANIC (("add param %u to bx_list_c id=%u: list capacity exceeded", param->get_id (), get_id ()));
+  list[size] = param;
+  size++;
+}
+
+bx_param_c *
+bx_list_c::get (int index)
+{
+  BX_ASSERT (index >= 0 && index < size);
+  return list[index];
+}
+
diff --git a/tools/ioemu/gui/siminterface.h b/tools/ioemu/gui/siminterface.h
new file mode 100644 (file)
index 0000000..9a02847
--- /dev/null
@@ -0,0 +1,1460 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: siminterface.h,v 1.113.2.2 2004/02/06 22:14:35 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Before I can describe what this file is for, I have to make the
+// distinction between a configuration interface (CI) and the VGA display
+// window (VGAW).  I will try to avoid the term 'GUI' because it is unclear 
+// if that means CI or VGAW, and because not all interfaces are graphical 
+// anyway.
+//
+// The traditional Bochs screen is a window with a large VGA display panel and
+// a series of buttons (floppy, cdrom, snapshot, power).  Over the years, we
+// have collected many implementations of the VGAW for different environments
+// and platforms; each implementation is in a separate file under gui/*:
+// x.cc, win32.cc, beos.cc, macintosh.cc, etc.  The files gui.h and gui.cc
+// define the platform independent part of the VGAW, leaving about 15 methods
+// of the bx_gui_c class undefined.  The platform dependent file must 
+// implement the remaining 15 methods.
+//
+// The configuration interface is relatively new, started by Bryce Denney in
+// June 2001.  The CI is intended to allow the user to edit a variety of
+// configuration and runtime options.  Some options, such as memory size or
+// enabling the ethernet card, should only be changed before the simulation
+// begins; others, such as floppy disk image, instructions per second, and
+// logging options can be safely changed at runtime.  The CI allows the user to
+// make these changes.  Before the CI existed, only a few things could be
+// changed at runtime, all linked to clicking on the VGAW buttons.
+//
+// At the time that the CI was conceived, we were still debating what form the
+// user interface part would take: stdin/stdout menus, a graphical application
+// with menus and dialogs running in a separate thread, or even a tiny web
+// server that you can connect to with a web browser.  As a result the
+// interface to the CI was designed so that the user interface of the CI 
+// could be replaced easily at compile time, or maybe even at runtime via
+// a plugin architecture.  To this end, we kept a clear separation between
+// the user interface code and the siminterface, the code that interfaces with
+// the simulator.  The same siminterface is used all the time, while 
+// different implementations of the CI can be switched in reasonably easily.
+// Only the CI code uses library specific graphics and I/O functions; the
+// siminterface deals in portable abstractions and callback functions.
+// The first CI implementation was a series of text mode menus implemented in
+// control.cc.
+//
+// The configuration interface MUST use the siminterface methods to access the
+// simulator.  It should not modify settings in some device with code like
+// bx_floppy.s.media[2].heads = 17.  If such access is needed, then a
+// siminterface method should be written to make the change on the CI's behalf.
+// This separation is enforced by the fact that the CI does not even include
+// bochs.h.  You'll notice that control.cc include osdep.h, control.h, and
+// siminterface.h, so it doesn't know what bx_floppy or bx_cpu_c are.  I'm sure
+// some people will say is overly restrictive and/or annoying.  When I set it
+// up this way, we were still talking about making the CI in a seperate
+// process, where direct method calls would be impossible.  Also, we have been
+// considering turning devices into plugin modules which are dynamically 
+// linked.  Any direct references to something like bx_floppy.s.media[2].heads
+// would have to be reworked before a plugin interface was possible as well.
+//
+// The siminterface is the glue between the CI and the simulator.  There is
+// just one global instance of the siminterface object, which can be referred
+// to by the global variable bx_simulator_interface_c *SIM; The base class
+// bx_simulator_interface_c, contains only virtual functions and it defines the
+// interface that the CI is allowed to use.  In siminterface.cc, a class
+// called bx_real_sim_c is defined with bx_simulator_interface_c as its parent
+// class.  Bx_real_sim_c implements each of the functions.  The separation into
+// parent class and child class leaves the possibility of making a different
+// child class that talks to the simulator in a different way (networking for
+// example).  If you were writing a user interface in a separate process, you
+// could define a subclass of bx_simulator_interface_c called
+// bx_siminterface_proxy_c which opens up a network port and turns all method
+// calls into network sends and receives.  Because the interface is defined
+// entirely by the base class, the code that calls the methods would not know
+// the difference.
+//
+// An important part of the siminterface implementation is the use of parameter
+// classes, or bx_param_*.  The parameter classes are described below, where
+// they are declared.  Search for "parameter classes" below for detals.
+//
+// Also this header file declares data structures for certain events that pass
+// between the siminterface and the CI.  Search for "event structures" below.
+
+
+
+//////////////////////////////////////////////////////
+// BX_UI_TEXT should be set to 1 when the text mode configuration interface
+// is compiled in.  This gives each type of parameter a text_print and text_ask
+// method (defined in gui/control.cc) so that you can call text_ask() on any
+// kind of parameter to ask the user to edit the value.
+//
+// I have been considering whether to use the same strategy for the
+// wxWindows interface, but I'm not sure if I like it.  One problem is
+// that in order to declare member functions that are useful for
+// wxWindows, the wxWindows header files would have to be included
+// before the param object definitions.  That means that all the
+// wxwindows headers would have be included when compiling every
+// single bochs file.  One of the things I like about the separation
+// between the simulator and CI is that the two parts can be
+// compiled without any knowledge of the other.  Bochs doesn't include
+// <wx.h>, and the wxwindows CI (wxmain.cc) doesn't need to include <bochs.h>.
+// Aside from making compiles faster, this enforces the use of the siminterface
+// so it keeps the interface clean (important when we may have multiple UI
+// implementations for example).  This argues for keeping UI-specific
+// structures out of the simulator interface.  It certainly works ok for the
+// text interface, but that's because FILE* is standard and portable.
+#define BX_UI_TEXT 1
+
+//////////////////////////////////////////////////////
+
+// list of possible types for bx_param_c and descendant objects
+typedef enum {
+  BXT_OBJECT = 201,
+  BXT_PARAM,
+  BXT_PARAM_NUM,
+  BXT_PARAM_BOOL,
+  BXT_PARAM_ENUM,
+  BXT_PARAM_STRING,
+  BXT_LIST
+} bx_objtype;
+
+// list if parameter id values.  The actual values are not important;
+// it's only important that they all be different from each other.
+typedef enum {
+  BXP_NULL = 301,
+  BXP_IPS,
+  BXP_REALTIME_PIT,
+  BXP_TEXT_SNAPSHOT_CHECK,
+  BXP_VGA_UPDATE_INTERVAL,
+  BXP_MOUSE_ENABLED,
+  BXP_MEM_SIZE,
+  BXP_ROM_PATH,
+  BXP_ROM_ADDRESS,
+  BXP_VGA_ROM_PATH,
+  BXP_OPTROM1_PATH,
+  BXP_OPTROM2_PATH,
+  BXP_OPTROM3_PATH,
+  BXP_OPTROM4_PATH,
+  BXP_OPTROM1_ADDRESS,
+  BXP_OPTROM2_ADDRESS,
+  BXP_OPTROM3_ADDRESS,
+  BXP_OPTROM4_ADDRESS,
+  BXP_KBD_SERIAL_DELAY,
+  BXP_KBD_PASTE_DELAY,
+  BXP_KBD_TYPE,
+  BXP_FLOPPY_CMD_DELAY,
+  BXP_FLOPPYA_DEVTYPE,
+  BXP_FLOPPYA_PATH,
+  BXP_FLOPPYA_TYPE,
+  BXP_FLOPPYA_STATUS,
+  BXP_FLOPPYA,
+  BXP_FLOPPYB_DEVTYPE,
+  BXP_FLOPPYB_PATH,
+  BXP_FLOPPYB_TYPE,
+  BXP_FLOPPYB_STATUS,
+  BXP_FLOPPYB,
+
+  BXP_ATA0_MENU,
+  BXP_ATA1_MENU,
+  BXP_ATA2_MENU,
+  BXP_ATA3_MENU,
+#define BXP_ATAx_MENU(i) (BXP_ATA0_MENU + (i))
+  BXP_ATA0,
+  BXP_ATA1,
+  BXP_ATA2,
+  BXP_ATA3,
+#define BXP_ATAx(i) (BXP_ATA0 + (i))
+  BXP_ATA0_PRESENT,
+  BXP_ATA1_PRESENT,
+  BXP_ATA2_PRESENT,
+  BXP_ATA3_PRESENT,
+#define BXP_ATAx_PRESENT(i) (BXP_ATA0_PRESENT + (i))
+  BXP_ATA0_IOADDR1,
+  BXP_ATA1_IOADDR1,
+  BXP_ATA2_IOADDR1,
+  BXP_ATA3_IOADDR1,
+#define BXP_ATAx_IOADDR1(i) (BXP_ATA0_IOADDR1 + (i))
+  BXP_ATA0_IOADDR2,
+  BXP_ATA1_IOADDR2,
+  BXP_ATA2_IOADDR2,
+  BXP_ATA3_IOADDR2,
+#define BXP_ATAx_IOADDR2(i) (BXP_ATA0_IOADDR2 + (i))
+  BXP_ATA0_IRQ,
+  BXP_ATA1_IRQ,
+  BXP_ATA2_IRQ,
+  BXP_ATA3_IRQ,
+#define BXP_ATAx_IRQ(i) (BXP_ATA0_IRQ + (i))
+
+  BXP_ATA0_MASTER,
+  BXP_ATA0_SLAVE,
+  BXP_ATA1_MASTER,
+  BXP_ATA1_SLAVE,
+  BXP_ATA2_MASTER,
+  BXP_ATA2_SLAVE,
+  BXP_ATA3_MASTER,
+  BXP_ATA3_SLAVE,
+#define BXP_ATAx_DEVICE(i, s) (BXP_ATA0_MASTER + (2*(i)) + (s))
+
+#define BXP_PARAMS_PER_ATA_DEVICE 12
+
+  BXP_ATA0_MASTER_PRESENT,
+  BXP_ATA0_SLAVE_PRESENT,
+  BXP_ATA1_MASTER_PRESENT,
+  BXP_ATA1_SLAVE_PRESENT,
+  BXP_ATA2_MASTER_PRESENT,
+  BXP_ATA2_SLAVE_PRESENT,
+  BXP_ATA3_MASTER_PRESENT,
+  BXP_ATA3_SLAVE_PRESENT,
+#define BXP_ATAx_DEVICE_PRESENT(i, s) (BXP_ATA0_MASTER_PRESENT + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_TYPE,
+  BXP_ATA0_SLAVE_TYPE,
+  BXP_ATA1_MASTER_TYPE,
+  BXP_ATA1_SLAVE_TYPE,
+  BXP_ATA2_MASTER_TYPE,
+  BXP_ATA2_SLAVE_TYPE,
+  BXP_ATA3_MASTER_TYPE,
+  BXP_ATA3_SLAVE_TYPE,
+#define BXP_ATAx_DEVICE_TYPE(i, s) (BXP_ATA0_MASTER_TYPE + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_MODE,
+  BXP_ATA0_SLAVE_MODE,
+  BXP_ATA1_MASTER_MODE,
+  BXP_ATA1_SLAVE_MODE,
+  BXP_ATA2_MASTER_MODE,
+  BXP_ATA2_SLAVE_MODE,
+  BXP_ATA3_MASTER_MODE,
+  BXP_ATA3_SLAVE_MODE,
+#define BXP_ATAx_DEVICE_MODE(i, s) (BXP_ATA0_MASTER_MODE + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_PATH,
+  BXP_ATA0_SLAVE_PATH,
+  BXP_ATA1_MASTER_PATH,
+  BXP_ATA1_SLAVE_PATH,
+  BXP_ATA2_MASTER_PATH,
+  BXP_ATA2_SLAVE_PATH,
+  BXP_ATA3_MASTER_PATH,
+  BXP_ATA3_SLAVE_PATH,
+#define BXP_ATAx_DEVICE_PATH(i, s) (BXP_ATA0_MASTER_PATH + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_CYLINDERS,
+  BXP_ATA0_SLAVE_CYLINDERS,
+  BXP_ATA1_MASTER_CYLINDERS,
+  BXP_ATA1_SLAVE_CYLINDERS,
+  BXP_ATA2_MASTER_CYLINDERS,
+  BXP_ATA2_SLAVE_CYLINDERS,
+  BXP_ATA3_MASTER_CYLINDERS,
+  BXP_ATA3_SLAVE_CYLINDERS,
+#define BXP_ATAx_DEVICE_CYLINDERS(i, s) (BXP_ATA0_MASTER_CYLINDERS + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_HEADS,
+  BXP_ATA0_SLAVE_HEADS,
+  BXP_ATA1_MASTER_HEADS,
+  BXP_ATA1_SLAVE_HEADS,
+  BXP_ATA2_MASTER_HEADS,
+  BXP_ATA2_SLAVE_HEADS,
+  BXP_ATA3_MASTER_HEADS,
+  BXP_ATA3_SLAVE_HEADS,
+#define BXP_ATAx_DEVICE_HEADS(i, s) (BXP_ATA0_MASTER_HEADS + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_SPT,
+  BXP_ATA0_SLAVE_SPT,
+  BXP_ATA1_MASTER_SPT,
+  BXP_ATA1_SLAVE_SPT,
+  BXP_ATA2_MASTER_SPT,
+  BXP_ATA2_SLAVE_SPT,
+  BXP_ATA3_MASTER_SPT,
+  BXP_ATA3_SLAVE_SPT,
+#define BXP_ATAx_DEVICE_SPT(i, s) (BXP_ATA0_MASTER_SPT + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_STATUS,
+  BXP_ATA0_SLAVE_STATUS,
+  BXP_ATA1_MASTER_STATUS,
+  BXP_ATA1_SLAVE_STATUS,
+  BXP_ATA2_MASTER_STATUS,
+  BXP_ATA2_SLAVE_STATUS,
+  BXP_ATA3_MASTER_STATUS,
+  BXP_ATA3_SLAVE_STATUS,
+#define BXP_ATAx_DEVICE_STATUS(i, s) (BXP_ATA0_MASTER_STATUS + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_MODEL,
+  BXP_ATA0_SLAVE_MODEL,
+  BXP_ATA1_MASTER_MODEL,
+  BXP_ATA1_SLAVE_MODEL,
+  BXP_ATA2_MASTER_MODEL,
+  BXP_ATA2_SLAVE_MODEL,
+  BXP_ATA3_MASTER_MODEL,
+  BXP_ATA3_SLAVE_MODEL,
+#define BXP_ATAx_DEVICE_MODEL(i, s) (BXP_ATA0_MASTER_MODEL + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_BIOSDETECT,
+  BXP_ATA0_SLAVE_BIOSDETECT,
+  BXP_ATA1_MASTER_BIOSDETECT,
+  BXP_ATA1_SLAVE_BIOSDETECT,
+  BXP_ATA2_MASTER_BIOSDETECT,
+  BXP_ATA2_SLAVE_BIOSDETECT,
+  BXP_ATA3_MASTER_BIOSDETECT,
+  BXP_ATA3_SLAVE_BIOSDETECT,
+#define BXP_ATAx_DEVICE_BIOSDETECT(i, s) (BXP_ATA0_MASTER_BIOSDETECT + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_TRANSLATION,
+  BXP_ATA0_SLAVE_TRANSLATION,
+  BXP_ATA1_MASTER_TRANSLATION,
+  BXP_ATA1_SLAVE_TRANSLATION,
+  BXP_ATA2_MASTER_TRANSLATION,
+  BXP_ATA2_SLAVE_TRANSLATION,
+  BXP_ATA3_MASTER_TRANSLATION,
+  BXP_ATA3_SLAVE_TRANSLATION,
+#define BXP_ATAx_DEVICE_TRANSLATION(i, s) (BXP_ATA0_MASTER_TRANSLATION + (2*(i)) + (s))
+
+  BXP_ATA0_MASTER_JOURNAL,
+  BXP_ATA0_SLAVE_JOURNAL,
+  BXP_ATA1_MASTER_JOURNAL,
+  BXP_ATA1_SLAVE_JOURNAL,
+  BXP_ATA2_MASTER_JOURNAL,
+  BXP_ATA2_SLAVE_JOURNAL,
+  BXP_ATA3_MASTER_JOURNAL,
+  BXP_ATA3_SLAVE_JOURNAL,
+#define BXP_ATAx_DEVICE_JOURNAL(i, s) (BXP_ATA0_MASTER_JOURNAL + (2*(i)) + (s))
+
+#define BXP_PARAMS_PER_SERIAL_PORT 2
+  BXP_COM1_ENABLED,
+  BXP_COM1_PATH,
+  BXP_COM2_ENABLED,
+  BXP_COM2_PATH,
+  BXP_COM3_ENABLED,
+  BXP_COM3_PATH,
+  BXP_COM4_ENABLED,
+  BXP_COM4_PATH,
+#define BXP_PARAMS_PER_USB_HUB 3
+  BXP_USB1_ENABLED,
+  BXP_USB1_IOADDR,
+  BXP_USB1_IRQ,
+  BXP_PRIVATE_COLORMAP,
+  BXP_FULLSCREEN,
+  BXP_SCREENMODE,
+  BXP_I440FX_SUPPORT,
+  BXP_NEWHARDDRIVESUPPORT,
+  BXP_LOG_FILENAME,
+  BXP_LOG_PREFIX,
+  BXP_DEBUGGER_LOG_FILENAME,
+  BXP_CMOS_PATH,
+  BXP_CMOS_IMAGE,
+  BXP_CLOCK,
+  BXP_CLOCK_TIME0,
+  BXP_CLOCK_SYNC,
+  BXP_LOAD32BITOS_WHICH,
+  BXP_LOAD32BITOS_PATH,
+  BXP_LOAD32BITOS_IOLOG,
+  BXP_LOAD32BITOS_INITRD,
+  BXP_LOAD32BITOS,
+  BXP_BOOTDRIVE,
+  BXP_FLOPPYSIGCHECK,
+  BXP_MENU_MAIN,
+  BXP_MENU_MEMORY,
+  BXP_MENU_INTERFACE,
+  BXP_MENU_DISK,
+  BXP_MENU_SERIAL_PARALLEL,
+  BXP_MENU_SOUND,
+  BXP_MENU_KEYBOARD,
+  BXP_MENU_MISC,
+  BXP_MENU_MISC_2,
+  BXP_MENU_RUNTIME,
+  BXP_MAX_IPS,
+  BXP_NE2K_PRESENT,
+  BXP_NE2K_IOADDR,
+  BXP_NE2K_IRQ,
+  BXP_NE2K_MACADDR,
+  BXP_NE2K_ETHMOD,
+  BXP_NE2K_ETHDEV,
+  BXP_NE2K_SCRIPT,
+  BXP_NE2K,
+  BXP_SB16_PRESENT,
+  BXP_SB16_MIDIFILE,
+  BXP_SB16_WAVEFILE,
+  BXP_SB16_LOGFILE,
+  BXP_SB16_MIDIMODE,
+  BXP_SB16_WAVEMODE,
+  BXP_SB16_LOGLEVEL,
+  BXP_SB16_DMATIMER,
+  BXP_SB16,
+#define BXP_PARAMS_PER_PARALLEL_PORT 2
+  BXP_PARPORT1_ENABLED,
+  BXP_PARPORT1_OUTFILE,
+  BXP_PARPORT2_ENABLED,
+  BXP_PARPORT2_OUTFILE,
+  BXP_KEYBOARD_USEMAPPING,
+  BXP_KEYBOARD_MAP,
+  BXP_KEYBOARD,
+  BXP_USER_SHORTCUT,
+  BXP_ASK_FOR_PATHNAME,   // for general file selection dialog
+  BXP_BOCHS_START,        // How Bochs starts
+  // experiment: add params for CPU registers
+  BXP_CPU_PARAMETERS,
+  BXP_CPU_EAX,
+  BXP_CPU_EBX,
+  BXP_CPU_ECX,
+  BXP_CPU_EDX,
+  BXP_CPU_EBP,
+  BXP_CPU_ESI,
+  BXP_CPU_EDI,
+  BXP_CPU_ESP,
+  BXP_CPU_EIP,
+  BXP_CPU_SEG_CS,
+  BXP_CPU_SEG_DS,
+  BXP_CPU_SEG_SS,
+  BXP_CPU_SEG_ES,
+  BXP_CPU_SEG_FS,
+  BXP_CPU_SEG_GS,
+  BXP_CPU_SEG_LDTR,
+  BXP_CPU_SEG_TR,
+  BXP_CPU_GDTR_BASE,
+  BXP_CPU_GDTR_LIMIT,
+  BXP_CPU_IDTR_BASE,
+  BXP_CPU_IDTR_LIMIT,
+  BXP_CPU_EFLAGS,
+  BXP_CPU_EFLAGS_ID,
+  BXP_CPU_EFLAGS_VIP,
+  BXP_CPU_EFLAGS_VIF,
+  BXP_CPU_EFLAGS_AC,
+  BXP_CPU_EFLAGS_VM,
+  BXP_CPU_EFLAGS_RF,
+  BXP_CPU_EFLAGS_NT,
+  BXP_CPU_EFLAGS_IOPL,
+  BXP_CPU_EFLAGS_OF,
+  BXP_CPU_EFLAGS_DF,
+  BXP_CPU_EFLAGS_IF,
+  BXP_CPU_EFLAGS_TF,
+  BXP_CPU_EFLAGS_SF,
+  BXP_CPU_EFLAGS_ZF,
+  BXP_CPU_EFLAGS_AF,
+  BXP_CPU_EFLAGS_PF,
+  BXP_CPU_EFLAGS_CF,
+  BXP_CPU_DR0,
+  BXP_CPU_DR1,
+  BXP_CPU_DR2,
+  BXP_CPU_DR3,
+  BXP_CPU_DR6,
+  BXP_CPU_DR7,
+  BXP_CPU_TR3,
+  BXP_CPU_TR4,
+  BXP_CPU_TR5,
+  BXP_CPU_TR6,
+  BXP_CPU_TR7,
+  BXP_CPU_CR0,
+  BXP_CPU_CR1,
+  BXP_CPU_CR2,
+  BXP_CPU_CR3,
+  BXP_CPU_CR4,
+  // a few parameters for the keyboard
+  BXP_KBD_PARAMETERS,
+  BXP_KBD_PARE,
+  BXP_KBD_TIM ,
+  BXP_KBD_AUXB,
+  BXP_KBD_KEYL,
+  BXP_KBD_C_D,
+  BXP_KBD_SYSF,
+  BXP_KBD_INPB,
+  BXP_KBD_OUTB,
+  BXP_KBD_TIMER_PENDING,
+  BXP_KBD_IRQ1_REQ,
+  BXP_KBD_IRQ12_REQ,
+#if BX_DEBUGGER
+  // in debugger, is the simulation running (continue command) or waiting.
+  // This is only modified by debugger code, not by the user.
+  BXP_DEBUG_RUNNING,
+#endif
+  BXP_SEL_CONFIG_INTERFACE,
+  BXP_SEL_DISPLAY_LIBRARY,
+  BXP_THIS_IS_THE_LAST    // used to determine length of list
+} bx_id;
+
+// use x=1,2,3,4
+#define BXP_COMx_ENABLED(x) \
+   (bx_id)(BXP_COM1_ENABLED + (((x)-1)*BXP_PARAMS_PER_SERIAL_PORT))
+#define BXP_COMx_PATH(x) \
+  (bx_id)(BXP_COM1_PATH + (((x)-1)*BXP_PARAMS_PER_SERIAL_PORT))
+
+// use x=1
+#define BXP_USBx_ENABLED(x) \
+   (bx_id)(BXP_USB1_ENABLED + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+#define BXP_USBx_IOADDR(x) \
+   (bx_id)(BXP_USB1_IOADDR + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+#define BXP_USBx_IRQ(x) \
+   (bx_id)(BXP_USB1_IRQ + (((x)-1)*BXP_PARAMS_PER_USB_HUB))
+
+// use x=1,2
+#define BXP_PARPORTx_ENABLED(x) \
+  (bx_id)(BXP_PARPORT1_ENABLED + (((x)-1)*BXP_PARAMS_PER_PARALLEL_PORT))
+#define BXP_PARPORTx_OUTFILE(x) \
+  (bx_id)(BXP_PARPORT1_OUTFILE + (((x)-1)*BXP_PARAMS_PER_PARALLEL_PORT))
+
+typedef enum {
+  BX_TOOLBAR_UNDEFINED,
+  BX_TOOLBAR_FLOPPYA,
+  BX_TOOLBAR_FLOPPYB,
+  BX_TOOLBAR_CDROMD,
+  BX_TOOLBAR_RESET,
+  BX_TOOLBAR_POWER,
+  BX_TOOLBAR_COPY,
+  BX_TOOLBAR_PASTE,
+  BX_TOOLBAR_SNAPSHOT,
+  BX_TOOLBAR_CONFIG,
+  BX_TOOLBAR_MOUSE_EN,
+  BX_TOOLBAR_USER
+} bx_toolbar_buttons;
+
+// Log level defines
+typedef enum {
+  LOGLEV_DEBUG = 0,
+  LOGLEV_INFO,
+  LOGLEV_ERROR,
+  LOGLEV_PANIC,
+  LOGLEV_PASS,
+  N_LOGLEV
+} bx_log_levels;
+
+// types of reset
+#define BX_RESET_SOFTWARE 10
+#define BX_RESET_HARDWARE 11
+
+//cdrom
+#define BX_EJECTED   10
+#define BX_INSERTED  11
+
+// boot devices
+#define BX_BOOT_FLOPPYA 0
+#define BX_BOOT_DISKC   1
+#define BX_BOOT_CDROM   2
+
+// loader hack
+#define Load32bitOSNone        0
+#define Load32bitOSLinux       1
+#define Load32bitOSNullKernel  2 // being developed for plex86
+#define Load32bitOSLast        2
+
+///////////////////////////////////////////////////////////////////
+// event structures for communication between simulator and CI
+///////////////////////////////////////////////////////////////////
+// Because the CI (configuration interface) might be in a different
+// thread or even a different process, we pass events encoded in data
+// structures to it instead of just calling functions.  Each type of
+// event is declared as a different structure, and then all those
+// structures are squished into a union in BxEvent.  (BTW, this is
+// almost exactly how X windows event structs work.)
+//
+// These are simple structs, unblemished by C++ methods and tricks.
+// No matter what event type it is, we allocate a BxEvent for each
+// one, as opposed to trying to save a few bytes on small events by
+// allocating only the bytes necessary for it.  This makes it easy and
+// fast to store events in a queue, like this
+//   BxEvent event_queue[MAX_EVENTS];
+//
+// Events come in two varieties: synchronous and asynchronous.  We
+// have to worry about sync and async events because the CI and the
+// simulation may be running in different threads.  An async event is
+// the simplest.  Whichever thread originates the event just builds
+// the data structure, sends it, and then continues with its business.
+// Async events can go in either direction.  Synchronous events
+// require the other thread to "respond" before the originating thread
+// can continue.  It's like a function with a return value; you can't
+// continue until you get the return value back.
+//
+// Examples:
+//
+// async event: In the wxWindows implementation, both the CI and the
+// VGAW operate in the wxWindows GUI thread.  When the user presses a
+// key, wxWindows sends a wxKeyEvent to the VGAW event handler code in
+// wx.cc.  The VGAW handler then builds a BxEvent with
+// type=BX_ASYNC_EVT_KEY, and fills in the bx_key and raw_scancode
+// fields.  The asynchronous event is placed on the event_queue for
+// the simulator, then the VGAW handler returns.  (With wxWindows and
+// many other graphical libaries, the event handler must return
+// quickly because the window will not be updated until it's done.)
+// Some time later, the simulator reaches the point where it checks
+// for new events from the user (actually controlled by
+// bx_keyb_c::periodic() in iodev/keyboard.cc) and calls
+// bx_gui.handle_events().  Then all the events in the queue are
+// processed by the simulator.  There is no "response" sent back to
+// the originating thread.
+//
+// sync event: Sometimes the simulator reaches a point where it needs
+// to ask the user how to proceed.  In this case, the simulator sends
+// a synchronous event because it requires a response before it can 
+// continue.  It builds an event structure, perhaps with type
+// BX_SYNC_EVT_ASK_PARAM, sends it to the user interface 
+// using the event handler function defined by set_notify_callback(),
+// and pauses the simulation.  The user interface asks the user the
+// question, and puts the answer into the BxEvent.retcode field.  The
+// event handler function returns the modified BxEvent with retcode
+// filled in, and the simulation continues.  The details of this
+// transaction can be complicated if the simulation and CI are not
+// in the same thread, but the behavior is as described.
+//
+
+///// types and definitions used in event structures
+
+#define BX_EVT_IS_ASYNC(type) ((type) > __ALL_EVENTS_BELOW_ARE_ASYNC__)
+
+typedef enum {
+  __ALL_EVENTS_BELOW_ARE_SYNCHRONOUS__ = 2000,
+  BX_SYNC_EVT_GET_PARAM,          // CI -> simulator -> CI
+  BX_SYNC_EVT_ASK_PARAM,          // simulator -> CI -> simulator
+  BX_SYNC_EVT_TICK,               // simulator -> CI, wait for response.
+  BX_SYNC_EVT_LOG_ASK,            // simulator -> CI, wait for response.
+  BX_SYNC_EVT_GET_DBG_COMMAND,    // simulator -> CI, wait for response.
+  __ALL_EVENTS_BELOW_ARE_ASYNC__,
+  BX_ASYNC_EVT_KEY,               // vga window -> simulator
+  BX_ASYNC_EVT_MOUSE,             // vga window -> simulator
+  BX_ASYNC_EVT_SET_PARAM,         // CI -> simulator
+  BX_ASYNC_EVT_LOG_MSG,           // simulator -> CI
+  BX_ASYNC_EVT_DBG_MSG,           // simulator -> CI
+  BX_ASYNC_EVT_VALUE_CHANGED,     // simulator -> CI
+  BX_ASYNC_EVT_TOOLBAR,           // CI -> simulator
+  BX_ASYNC_EVT_REFRESH            // simulator -> CI
+} BxEventType;
+
+typedef union {
+  Bit32s s32;
+  char *charptr;
+} AnyParamVal;
+
+// Define substructures which make up the interior of BxEvent.  The
+// substructures, such as BxKeyEvent or BxMouseEvent, should never be
+// allocated on their own.  They are only intended to be used within
+// the union in the BxEvent structure.
+
+// Event type: BX_SYNC_EVT_TICK
+//
+// A tick event is synchronous, sent from the simulator to the GUI.  The
+// event doesn't do anything visible.  Primarily it gives the GUI a chance
+// to tell the simulator to quit, if necessary.  There may be other uses
+// for the tick in the future, such as giving some kind of regular
+// status report or mentioning watched values that changed, but so far
+// it's just for that one thing.  There is no data associated with a
+// tick event.
+
+// Event type: BX_ASYNC_EVT_KEY
+//
+// A key event can be sent from the VGA window to the Bochs simulator.  
+// It is asynchronous.
+typedef struct {
+  // what was pressed?  This is a BX_KEY_* value.  For key releases,
+  // BX_KEY_RELEASED is ORed with the base BX_KEY_*.
+  Bit32u bx_key;
+  bx_bool raw_scancode;
+} BxKeyEvent;
+
+// Event type: BX_ASYNC_EVT_MOUSE
+//
+// A mouse event can be sent from the VGA window to the Bochs
+// simulator.  It is asynchronous.  Currently unused because mouse
+// events aren't implemented in our wxWindows code yet.
+typedef struct {
+  // type is BX_EVT_MOUSE
+  Bit16s dx, dy;           // mouse motion delta
+  Bit8u buttons;           // which buttons are pressed.
+                           // bit 0: 1=left button down, 0=up
+                           // bit 1: 1=right button down, 0=up
+} BxMouseEvent;
+
+// Event type: BX_SYNC_EVT_GET_PARAM, BX_ASYNC_EVT_SET_PARAM
+//
+// Parameter set/get events are initiated by the CI, since Bochs can
+// always access the parameters directly.  So far, I haven't used
+// these event types.  In the CI I just call
+// SIM->get_param(parameter_id) to get a pointer to the bx_param_c
+// object and then call the get/set methods.  This is okay for
+// configuration since bochs is not running.  However it could be
+// dangerous for the GUI thread to poke around in Bochs structures
+// while the thread is running.  For these cases, I may have to be
+// more careful and actually build get/set events and place them on
+// Bochs's event queue to be processed during SIM->periodic() or
+// something.
+typedef struct {
+  // type is BX_EVT_GET_PARAM, BX_EVT_SET_PARAM
+  class bx_param_c *param;         // pointer to param structure
+  AnyParamVal val;
+} BxParamEvent;
+
+// Event type: BX_SYNC_EVT_ASK_PARAM
+// Synchronous event sent from the simulator to the CI.  This tells the
+// CI to ask the user to choose the value of a parameter.  The CI may 
+// need to discover the type of parameter so that it can use the right
+// kind of graphical display.  The BxParamEvent is used for these events
+// too.
+// FIXME: at the moment the GUI implements the ASK_PARAM event for just
+// a few parameter types.  I need to implement the event for all parameter
+// types.
+
+// Event type: BX_ASYNC_EVT_VALUE_CHANGED
+// 
+// Asynchronous event sent from the simulator to the CI, telling it that
+// some value that it (hopefully) cares about has changed.  This isn't
+// being used yet, but a good example is in a debugger interface, you might
+// want to maintain a reasonably current display of the PC or some other
+// simulation state.  The CI would set some kind of event mask (which
+// doesn't exist now of course) and then when certain values change, the
+// simulator would send this event so that the CI can update.  We may need
+// some kind of "flow control" since the simulator will be able to produce
+// new events much faster than the gui can accept them.
+
+// Event type: BX_ASYNC_EVT_LOG_MSG   (unused)
+//
+// Asynchronous event from the simulator to the CI.  When a BX_PANIC,
+// BX_ERROR, BX_INFO, or BX_DEBUG is found in the simulator code, this 
+// event type can be used to inform the CI of the condition.  There is
+// no point in sending messages to the CI that will not be displayed; these
+// would only slow the simulation.  So we will need some mechanism for 
+// choosing what kinds of events will be delivered to the CI.  Normally,
+// you wouldn't want to look at the log unless something is going wrong.
+// At that point, you might want to open up a window to watch the debug
+// messages from one or two devices only.
+//
+// Idea: Except for panics that require user attention to continue, it
+// might be most efficient to just append log messages to a file.
+// When the user wants to look at the log messages, the gui can reopen
+// the file (read only), skip to the end, and look backward for a
+// reasonable number of lines to display (200?).  This allows it to
+// skip over huge bursts of log entries without allocating memory,
+// synchronizing threads, etc. for each.
+typedef struct {
+  Bit8u level;
+  const char *prefix;
+  const char *msg;
+} BxLogMsgEvent;
+
+// Event type: BX_ASYNC_EVT_DBG_MSG   (unused)
+//
+// Also uses BxLogMsgEvent, but this is a message to be displayed in
+// the debugger history window.
+
+// Event type: BX_SYNC_EVT_LOG_ASK
+//
+// This is a synchronous version of BX_ASYNC_EVT_LOG_MSG, which is used
+// when the "action=ask" setting is used.  If the simulator runs into a
+// panic, it sends a synchronous BX_SYNC_EVT_LOG_ASK to the CI to be
+// displayed.  The CI shows a dialog that asks if the user wants to 
+// continue, quit, etc. and sends the answer back to the simulator.
+// This event also uses BxLogMsgEvent.
+enum {
+  BX_LOG_ASK_CHOICE_CONTINUE,
+  BX_LOG_ASK_CHOICE_CONTINUE_ALWAYS,
+  BX_LOG_ASK_CHOICE_DIE,
+  BX_LOG_ASK_CHOICE_DUMP_CORE,
+  BX_LOG_ASK_CHOICE_ENTER_DEBUG,
+  BX_LOG_ASK_N_CHOICES
+};
+
+// Event type: BX_SYNC_EVT_GET_DBG_COMMAND
+//
+// This is a synchronous event sent from the simulator to the debugger
+// requesting the next action.  In a text mode debugger, this would prompt
+// the user for the next command.  When a new command is ready, the
+// synchronous event is sent back with its fields filled in.
+typedef struct {
+  char *command;   // null terminated string. allocated by debugger interface
+                   // with new operator, freed by simulator with delete.
+} BxDebugCommand;
+
+
+
+// Event type: BX_EVT_TOOLBAR
+// Asynchronous event from the VGAW to the simulator, sent when the user
+// clicks on a toolbar button.  This may one day become something more 
+// general, like a command event, but at the moment it's only needed for
+// the toolbar events.
+typedef struct {
+  bx_toolbar_buttons button;
+  bool on;   // for toggling buttons, on=true means the toolbar button is
+             // pressed. on=false means it is not pressed.
+} BxToolbarEvent;
+
+// The BxEvent structure should be used for all events.  Every event has
+// a type and a spot for a return code (only used for synchronous events).
+typedef struct {
+  BxEventType type; // what kind is this?
+  Bit32s retcode;   // sucess or failure. only used for synchronous events.
+  union {
+    BxKeyEvent key;
+    BxMouseEvent mouse;
+    BxParamEvent param;
+    BxLogMsgEvent logmsg;
+    BxToolbarEvent toolbar;
+    BxDebugCommand debugcmd;
+  } u;
+} BxEvent;
+
+
+////////////////////////////////////////////////////////////////////
+// parameter classes: bx_param_c and family
+////////////////////////////////////////////////////////////////////
+//
+// All variables that can be configured through the CI are declared as
+// "parameters" or objects of type bx_param_*.  There is a bx_param_*
+// class for each type of data that the user would need to see and
+// edit, e.g. integer, boolean, enum, string, filename, or list of
+// other parameters.  The purpose of the bx_param_* class, in addition
+// to storing the parameter's value, is to hold the name, description,
+// and constraints on the value.  The bx_param_* class should hold
+// everything that the CI would need to display the value and allow
+// the user to modify it.  For integer parameters, the minimum and
+// maximum allowed value can be defined, and the base in which it
+// should be displayed and interpreted.  For enums, the
+// bx_param_enum_c structure includes the list of values which the
+// parameter can have.
+//
+// Also, some parameter classes support get/set callback functions to
+// allow arbitrary code to be executed when the parameter is get/set. 
+// An example of where this is useful: if you disable the NE2K card,
+// the set() handler for that parameter can tell the user interface
+// that the NE2K's irq, I/O address, and mac address should be
+// disabled (greyed out, hidden, or made inaccessible).  The get/set
+// methods can also check if the set() value is acceptable using
+// whatever means and override it.
+//
+// The parameter concept is similar to the use of parameters in JavaBeans.
+
+class bx_object_c;
+class bx_param_c;
+class bx_param_num_c;
+class bx_param_enum_c;
+class bx_param_bool_c;
+class bx_param_string_c;
+class bx_param_filename_c;
+class bx_list_c;
+
+class BOCHSAPI bx_object_c {
+private:
+  bx_id id;
+  bx_objtype type;
+protected:
+  void set_type (bx_objtype type);
+public:
+  bx_object_c (bx_id id);
+  bx_id get_id () { return id; }
+  Bit8u get_type () { return type; }
+};
+
+class BOCHSAPI bx_param_c : public bx_object_c {
+  BOCHSAPI_CYGONLY static const char *default_text_format;
+protected:
+  char *name;
+  char *description;
+  char *label; // label string for text menus and gui dialogs
+  const char *text_format;  // printf format string. %d for ints, %s for strings, etc.
+  char *ask_format;  // format string for asking for a new value
+  int runtime_param;
+  int enabled;
+public:
+  bx_param_c (bx_id id, char *name, char *description);
+  void set_format (const char *format) {text_format = format;}
+  const char *get_format () {return text_format;}
+  void set_ask_format (char *format) {ask_format = format; }
+  char *get_ask_format () {return ask_format;}
+  void set_label (char *text) {label = text;}
+  char *get_label () {return label;}
+  void set_runtime_param (int val) { runtime_param = val; }
+  int get_runtime_param () { return runtime_param; }
+  char *get_name () { return name; }
+  char *get_description () { return description; }
+  int get_enabled () { return enabled; }
+  virtual void set_enabled (int enabled) { this->enabled = enabled; }
+  void reset () {}
+  int getint () {return -1;}
+  static const char* set_default_format (const char *f);
+  static const char *get_default_format () { return default_text_format; }
+  virtual bx_list_c *get_dependent_list () { return NULL; }
+#if BX_UI_TEXT
+  virtual void text_print (FILE *fp) {}
+  virtual int text_ask (FILE *fpin, FILE *fpout) {return -1;}
+#endif
+};
+
+typedef Bit64s (*param_event_handler)(class bx_param_c *, int set, Bit64s val);
+typedef int (*param_enable_handler)(class bx_param_c *, int en);
+
+class BOCHSAPI bx_param_num_c : public bx_param_c {
+  BOCHSAPI_CYGONLY static Bit32u default_base;
+  // The dependent_list is initialized to NULL.  If dependent_list is modified
+  // to point to a bx_list_c of other parameters, the set() method of
+  // bx_param_bool_c will enable those parameters when this bool is true, and
+  // disable them when this bool is false.
+  bx_list_c *dependent_list;
+  void update_dependents ();
+protected:
+  Bit64s min, max, initial_val;
+  union _uval_ {
+    Bit64s number;   // used by bx_param_num_c
+    Bit64s *p64bit;  // used by bx_shadow_num_c
+    Bit32s *p32bit;  // used by bx_shadow_num_c
+    Bit16s *p16bit;  // used by bx_shadow_num_c
+    Bit8s  *p8bit;    // used by bx_shadow_num_c
+    bx_bool *pbool;  // used by bx_shadow_bool_c
+  } val;
+  param_event_handler handler;
+  param_enable_handler enable_handler;
+  int base;
+  Bit32u options;
+public:
+  enum {
+    // When a bx_param_num_c is displayed in dialog, USE_SPIN_CONTROL controls
+    // whether a spin control should be used instead of a simple text control.
+    USE_SPIN_CONTROL = (1<<0)
+  } bx_numopt_bits;
+  bx_param_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit64s min, Bit64s max, Bit64s initial_val);
+  void reset ();
+  void set_handler (param_event_handler handler);
+  void set_enable_handler (param_enable_handler handler);
+  virtual bx_list_c *get_dependent_list () { return dependent_list; }
+  void set_dependent_list (bx_list_c *l);
+  virtual void set_enabled (int enabled);
+  virtual Bit32s get () { return (Bit32s) get64(); }
+  virtual Bit64s get64 ();
+  virtual void set (Bit64s val);
+  void set_base (int base) { this->base = base; }
+  void set_initial_val (Bit64s initial_val);
+  int get_base () { return base; }
+  void set_range (Bit64u min, Bit64u max);
+  Bit64s get_min () { return min; }
+  Bit64s get_max () { return max; }
+  static Bit32u set_default_base (Bit32u val);
+  static Bit32u get_default_base () { return default_base; }
+  void set_options (Bit32u options) { this->options = options; }
+  Bit32u get_options () { return options; }
+#if BX_UI_TEXT
+  virtual void text_print (FILE *fp);
+  virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// a bx_shadow_num_c is like a bx_param_num_c except that it doesn't
+// store the actual value with its data. Instead, it uses val.p32bit
+// to keep a pointer to the actual data.  This is used to register
+// existing variables as parameters, without have to access it via
+// set/get methods.
+class BOCHSAPI bx_shadow_num_c : public bx_param_num_c {
+  Bit8u varsize;   // must be 64, 32, 16, or 8
+  Bit8u lowbit;   // range of bits associated with this param
+  Bit64u mask;     // mask is ANDed with value before it is returned from get
+public:
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit64s *ptr_to_real_val,
+      Bit8u highbit = 63,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit64u *ptr_to_real_val,
+      Bit8u highbit = 63,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit32s *ptr_to_real_val,
+      Bit8u highbit = 31,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit32u *ptr_to_real_val,
+      Bit8u highbit = 31,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit16s *ptr_to_real_val,
+      Bit8u highbit = 15,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit16u *ptr_to_real_val,
+      Bit8u highbit = 15,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit8s *ptr_to_real_val,
+      Bit8u highbit = 7,
+      Bit8u lowbit = 0);
+  bx_shadow_num_c (bx_id id,
+      char *name,
+      char *description,
+      Bit8u *ptr_to_real_val,
+      Bit8u highbit = 7,
+      Bit8u lowbit = 0);
+  virtual Bit64s get64 ();
+  virtual void set (Bit64s val);
+};
+
+class BOCHSAPI bx_param_bool_c : public bx_param_num_c {
+  // many boolean variables are used to enable/disable modules.  In the
+  // user interface, the enable variable should enable/disable all the
+  // other parameters associated with that module.
+public:
+  bx_param_bool_c (bx_id id, 
+      char *name,
+      char *description,
+      Bit64s initial_val);
+#if BX_UI_TEXT
+  virtual void text_print (FILE *fp);
+  virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// a bx_shadow_bool_c is a shadow param based on bx_param_bool_c.
+class BOCHSAPI bx_shadow_bool_c : public bx_param_bool_c {
+  // each bit of a bitfield can be a separate value.  bitnum tells which
+  // bit is used.  get/set will only modify that bit.
+  Bit8u bitnum;
+public:
+  bx_shadow_bool_c (bx_id id,
+      char *name,
+      char *description,
+      bx_bool *ptr_to_real_val,
+      Bit8u bitnum = 0);
+  virtual Bit64s get64 ();
+  virtual void set (Bit64s val);
+};
+
+
+class BOCHSAPI bx_param_enum_c : public bx_param_num_c {
+  char **choices;
+public:
+  bx_param_enum_c (bx_id id, 
+      char *name,
+      char *description,
+      char **choices,
+      Bit64s initial_val,
+      Bit64s value_base = 0);
+  char *get_choice (int n) { return choices[n]; }
+  int find_by_name (const char *string);
+  bool set_by_name (const char *string);
+#if BX_UI_TEXT
+  virtual void text_print (FILE *fp);
+  virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+typedef char* (*param_string_event_handler)(class bx_param_string_c *, int set, char *val, int maxlen);
+
+class BOCHSAPI bx_param_string_c : public bx_param_c {
+  int maxsize;
+  char *val, *initial_val;
+  param_string_event_handler handler;
+  param_enable_handler enable_handler;
+  bx_param_num_c *options;
+  char separator;
+public:
+  enum {
+    RAW_BYTES = 1,         // use binary text editor, like MAC addr
+    IS_FILENAME = 2,       // 1=yes it's a filename, 0=not a filename.
+                           // Some guis have a file browser. This
+                           // bit suggests that they use it.
+    SAVE_FILE_DIALOG = 4   // Use save dialog opposed to open file dialog
+  } bx_string_opt_bits;
+  bx_param_string_c (bx_id id,
+      char *name,
+      char *description,
+      char *initial_val,
+      int maxsize=-1);
+  virtual ~bx_param_string_c ();
+  void reset ();
+  void set_handler (param_string_event_handler handler);
+  void set_enable_handler (param_enable_handler handler);
+  virtual void set_enabled (int enabled);
+  Bit32s get (char *buf, int len);
+  char *getptr () {return val; }
+  void set (char *buf);
+  bx_bool equals (const char *buf);
+  bx_param_num_c *get_options () { return options; }
+  void set_separator (char sep) {separator = sep; }
+  char get_separator () {return separator; }
+  int get_maxsize () {return maxsize; }
+#if BX_UI_TEXT
+  virtual void text_print (FILE *fp);
+  virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+// Declare a filename class.  It is identical to a string, except that
+// it initializes the options differently.  This is just a shortcut
+// for declaring a string param and setting the options with IS_FILENAME.
+class BOCHSAPI bx_param_filename_c : public bx_param_string_c {
+public:
+  bx_param_filename_c (bx_id id,
+      char *name,
+      char *description,
+      char *initial_val,
+      int maxsize=-1);
+};
+
+class BOCHSAPI bx_list_c : public bx_param_c {
+private:
+  // just a list of bx_param_c objects.  size tells current number of
+  // objects in the list, and maxsize tells how many list items are
+  // allocated in the constructor.
+  bx_param_c **list;
+  int size, maxsize;
+  // options is a bit field whose bits are defined by bx_listopt_bits ORed
+  // together.  Options is a bx_param so that if necessary the bx_list could
+  // install a handler to cause get/set of options to have side effects.
+  bx_param_num_c *options;
+  // for a menu, the value of choice before the call to "ask" is default.
+  // After ask, choice holds the value that the user chose.  Choice defaults
+  // to 1 in the constructor.
+  bx_param_num_c *choice;
+  // title of the menu or series
+  bx_param_string_c *title;
+  // if the menu shows a "return to previous menu" type of choice,
+  // this controls where that choice will go.
+  bx_param_c *parent;
+  void init ();
+public:
+  enum {
+    // When a bx_list_c is displayed as a menu, SHOW_PARENT controls whether or
+    // not the menu shows a "Return to parent menu" choice or not.
+    SHOW_PARENT = (1<<0),
+    // Some lists are best displayed shown as menus, others as a series of
+    // related questions.  This bit suggests to the CI that the series of
+    // questions format is preferred.
+    SERIES_ASK = (1<<1),
+    // When a bx_list_c is displayed in a dialog, USE_TAB_WINDOW suggests
+    // to the CI that each item in the list should be shown as a separate
+    // tab.  This would be most appropriate when each item is another list
+    // of parameters.
+    USE_TAB_WINDOW = (1<<2),
+    // When a bx_list_c is displayed in a dialog, the list name is used as the
+    // label of the group box if USE_BOX_TITLE is set. This is only necessary if
+    // more than one list appears in a dialog box.
+    USE_BOX_TITLE = (1<<3)
+  } bx_listopt_bits;
+  bx_list_c (bx_id id, int maxsize);
+  bx_list_c (bx_id id, char *name, char *description, bx_param_c **init_list);
+  bx_list_c (bx_id id, char *name, char *description, int maxsize);
+  virtual ~bx_list_c();
+  bx_list_c *clone ();
+  void add (bx_param_c *param);
+  bx_param_c *get (int index);
+  int get_size () { return size; }
+  bx_param_num_c *get_options () { return options; }
+  void set_options (bx_param_num_c *newopt) { options = newopt; }
+  bx_param_num_c *get_choice () { return choice; }
+  bx_param_string_c *get_title () { return title; }
+  void set_parent (bx_param_c *newparent) { parent = newparent; }
+  bx_param_c *get_parent () { return parent; }
+#if BX_UI_TEXT
+  virtual void text_print (FILE *);
+  virtual int text_ask (FILE *fpin, FILE *fpout);
+#endif
+};
+
+////////////////////////////////////////////////////////////////
+
+
+// These are the different start modes.
+enum {
+  // Just start the simulation without running the configuration interface
+  // at all, unless something goes wrong.
+  BX_QUICK_START = 200,
+  // Run the configuration interface.  The default action will be to load a
+  // configuration file.  This makes sense if a config file could not be
+  // loaded, either because it wasn't found or because it had errors.
+  BX_LOAD_START,
+  // Run the configuration interface.  The default action will be to
+  // edit the configuration.
+  BX_EDIT_START,
+  // Run the configuration interface, but make the default action be to
+  // start the simulation.
+  BX_RUN_START
+};
+
+#define BX_FLOPPY_NONE   10 // floppy not present
+#define BX_FLOPPY_1_2    11 // 1.2M  5.25"
+#define BX_FLOPPY_1_44   12 // 1.44M 3.5"
+#define BX_FLOPPY_2_88   13 // 2.88M 3.5"
+#define BX_FLOPPY_720K   14 // 720K  3.5"
+#define BX_FLOPPY_360K   15 // 360K  5.25"
+#define BX_FLOPPY_160K   16 // 160K  5.25"
+#define BX_FLOPPY_180K   17 // 180K  5.25"
+#define BX_FLOPPY_320K   18 // 320K  5.25"
+#define BX_FLOPPY_LAST   18 // last legal value of floppy type
+
+#define BX_FLOPPY_GUESS  20 // decide based on image size
+
+#define BX_ATA_DEVICE_DISK      0
+#define BX_ATA_DEVICE_CDROM     1
+#define BX_ATA_DEVICE_LAST      1
+
+#define BX_ATA_BIOSDETECT_NONE      0
+#define BX_ATA_BIOSDETECT_AUTO      1
+#define BX_ATA_BIOSDETECT_CMOS      2
+
+#define BX_ATA_TRANSLATION_NONE      0
+#define BX_ATA_TRANSLATION_LBA       1
+#define BX_ATA_TRANSLATION_LARGE     2
+#define BX_ATA_TRANSLATION_RECHS     3
+#define BX_ATA_TRANSLATION_AUTO      4
+#define BX_ATA_TRANSLATION_LAST      4
+
+#define BX_ATA_MODE_FLAT        0
+#define BX_ATA_MODE_CONCAT      1
+#define BX_ATA_MODE_EXTDISKSIM  2
+#define BX_ATA_MODE_DLL_HD      3
+#define BX_ATA_MODE_SPARSE      4
+#define BX_ATA_MODE_VMWARE3     5
+#define BX_ATA_MODE_UNDOABLE    6
+#define BX_ATA_MODE_GROWING     7
+#define BX_ATA_MODE_VOLATILE    8
+#define BX_ATA_MODE_LAST        8
+//#define BX_ATA_MODE_Z_UNDOABLE  9
+//#define BX_ATA_MODE_Z_VOLATILE  10
+//#define BX_ATA_MODE_SPLIT       6
+
+#define BX_CLOCK_SYNC_NONE     0
+#define BX_CLOCK_SYNC_REALTIME 1
+#define BX_CLOCK_SYNC_SLOWDOWN 2
+#define BX_CLOCK_SYNC_BOTH     3
+#define BX_CLOCK_SYNC_LAST     3
+
+#define BX_CLOCK_TIME0_LOCAL     1
+#define BX_CLOCK_TIME0_UTC       2
+
+BOCHSAPI extern char *bochs_start_names[];
+BOCHSAPI extern int n_bochs_start_names;
+BOCHSAPI extern char *floppy_type_names[];
+BOCHSAPI extern int floppy_type_n_sectors[];
+BOCHSAPI extern int n_floppy_type_names;
+BOCHSAPI extern char *floppy_status_names[];
+BOCHSAPI extern int n_floppy_status_names;
+BOCHSAPI extern char *floppy_bootdisk_names[];
+BOCHSAPI extern int n_floppy_bootdisk_names;
+BOCHSAPI extern char *loader_os_names[];
+BOCHSAPI extern int n_loader_os_names;
+BOCHSAPI extern char *keyboard_type_names[];
+BOCHSAPI extern int n_keyboard_type_names;
+BOCHSAPI extern char *atadevice_type_names[];
+BOCHSAPI extern int n_atadevice_type_names;
+BOCHSAPI extern char *atadevice_mode_names[];
+BOCHSAPI extern int n_atadevice_mode_names;
+BOCHSAPI extern char *atadevice_status_names[];
+BOCHSAPI extern int n_atadevice_status_names;
+BOCHSAPI extern char *atadevice_biosdetect_names[];
+BOCHSAPI extern int n_atadevice_biosdetect_names;
+BOCHSAPI extern char *atadevice_translation_names[];
+BOCHSAPI extern int n_atadevice_translation_names;
+BOCHSAPI extern char *clock_sync_names[];
+BOCHSAPI extern int clock_sync_n_names;
+
+typedef struct {
+  bx_param_enum_c *Odevtype;
+  bx_param_string_c *Opath;
+  bx_param_enum_c *Otype;
+  bx_param_enum_c *Ostatus;
+  } bx_floppy_options;
+
+typedef struct {
+  bx_list_c *Omenu;
+  bx_param_bool_c *Opresent;
+  bx_param_enum_c *Otype;
+  bx_param_enum_c *Omode;
+  bx_param_string_c *Opath;
+  bx_param_string_c *Ojournal;
+  bx_param_num_c *Ocylinders;
+  bx_param_num_c *Oheads;
+  bx_param_num_c *Ospt;
+  bx_param_enum_c *Ostatus;
+  bx_param_string_c *Omodel;
+  bx_param_enum_c *Obiosdetect;
+  bx_param_enum_c *Otranslation;
+  } bx_atadevice_options;
+
+typedef struct {
+  bx_param_bool_c *Oenabled;
+  bx_param_string_c *Odev;
+  } bx_serial_options;
+
+typedef struct {
+  bx_param_bool_c *Oenabled;
+  bx_param_num_c *Oioaddr;
+  bx_param_num_c *Oirq;
+  } bx_usb_options;
+
+
+////////////////////////////////////////////////////////////////////
+// base class simulator interface, contains just virtual functions.
+// I'm not longer sure that having a base class is going to be of any
+// use... -Bryce
+
+#include <setjmp.h>
+
+enum ci_command_t { CI_START, CI_RUNTIME_CONFIG, CI_SHUTDOWN };
+enum ci_return_t { 
+  CI_OK,                  // normal return value 
+  CI_ERR_NO_TEXT_CONSOLE  // err: can't work because there's no text console
+  };
+typedef int (*config_interface_callback_t)(void *userdata, ci_command_t command);
+
+// bx_gui->set_display_mode() changes the mode between the configuration
+// interface and the simulation.  This is primarily intended for display
+// libraries which have a full-screen mode such as SDL, term, and svgalib.  The
+// display mode is set to DISP_MODE_CONFIG before displaying any configuration
+// menus, for panics that requires user input, when entering the debugger, etc.
+// It is set to DISP_MODE_SIM when the Bochs simulation resumes.  The constants
+// are defined here so that configuration interfaces can use them with the
+// bx_simulator_interface_c::set_display_mode() method.
+enum disp_mode_t { DISP_MODE_CONFIG=100, DISP_MODE_SIM };
+
+class BOCHSAPI bx_simulator_interface_c {
+public:
+  bx_simulator_interface_c ();
+  virtual void set_quit_context (jmp_buf *context) {}
+  virtual int get_init_done () { return -1; }
+  virtual int set_init_done (int n) {return -1;}
+  virtual void get_param_id_range (int *min, int *max) {}
+  virtual int register_param (bx_id id, bx_param_c *it) {return -1;}
+  virtual void reset_all_param () {}
+  virtual bx_param_c *get_param (bx_id id) {return NULL;}
+  virtual bx_param_num_c *get_param_num (bx_id id) {return NULL;}
+  virtual bx_param_string_c *get_param_string (bx_id id) {return NULL;}
+  virtual bx_param_bool_c *get_param_bool (bx_id id) {return NULL;}
+  virtual bx_param_enum_c *get_param_enum (bx_id id) {return NULL;}
+  virtual int get_n_log_modules () {return -1;}
+  virtual char *get_prefix (int mod) {return 0;}
+  virtual int get_log_action (int mod, int level) {return -1;}
+  virtual void set_log_action (int mod, int level, int action) {}
+  virtual int get_default_log_action (int level) {return -1;}
+  virtual void set_default_log_action (int level, int action) {}
+  virtual char *get_action_name (int action) {return 0;}
+  virtual const char *get_log_level_name (int level) {return 0;}
+  virtual int get_max_log_level () {return -1;}
+
+  // exiting is somewhat complicated!  The preferred way to exit bochs is
+  // to call BX_EXIT(exitcode).  That is defined to call 
+  // SIM->quit_sim(exitcode).  The quit_sim function first calls
+  // the cleanup functions in bochs so that it can destroy windows
+  // and free up memory, then sends a notify message to the CI 
+  // telling it that bochs has stopped.
+  virtual void quit_sim (int code) {}
+
+  virtual int get_exit_code () { return 0; }
+
+  virtual int get_default_rc (char *path, int len) {return -1;}
+  virtual int read_rc (char *path) {return -1;}
+  virtual int write_rc (char *rc, int overwrite) {return -1;}
+  virtual int get_log_file (char *path, int len) {return -1;}
+  virtual int set_log_file (char *path) {return -1;}
+  virtual int get_log_prefix (char *prefix, int len) {return -1;}
+  virtual int set_log_prefix (char *prefix) {return -1;}
+  virtual int get_debugger_log_file (char *path, int len) {return -1;}
+  virtual int set_debugger_log_file (char *path) {return -1;}
+  virtual int get_floppy_options (int drive, bx_floppy_options *out) {return -1;}
+  virtual int get_cdrom_options (int drive, bx_atadevice_options *out, int *where = NULL) {return -1;}
+  virtual char *get_floppy_type_name (int type) {return NULL;}
+
+  // The CI calls set_notify_callback to register its event handler function.
+  // This event handler function is called whenever the simulator needs to
+  // send an event to the CI.  For example, if the simulator hits a panic and
+  // wants to ask the user how to proceed, it would call the CI event handler
+  // to ask the CI to display a dialog.
+  //
+  // NOTE: At present, the standard VGAW buttons (floppy, snapshot, power,
+  // etc.) are displayed and handled by gui.cc, not by the CI or siminterface.
+  // gui.cc uses its own callback functions to implement the behavior of
+  // the buttons.  Some of these implementations call the siminterface.
+  typedef BxEvent* (*bxevent_handler)(void *theclass, BxEvent *event);
+  virtual void set_notify_callback (bxevent_handler func, void *arg) {}
+  virtual void get_notify_callback (bxevent_handler *func, void **arg) {}
+
+  // send an event from the simulator to the CI.
+  virtual BxEvent* sim_to_ci_event (BxEvent *event) {return NULL;}
+
+  // called from simulator when it hits serious errors, to ask if the user
+  // wants to continue or not
+  virtual int log_msg (const char *prefix, int level, const char *msg) {return -1;}
+
+  // tell the CI to ask the user for the value of a parameter.
+  virtual int ask_param (bx_id param) {return -1;}
+
+  // ask the user for a pathname
+  virtual int ask_filename (char *filename, int maxlen, char *prompt, char *the_default, int flags) {return -1;}
+  // called at a regular interval, currently by the keyboard handler.
+  virtual void periodic () {}
+  virtual int create_disk_image (const char *filename, int sectors, bx_bool overwrite) {return -3;}
+  // Tell the configuration interface (CI) that some parameter values have
+  // changed.  The CI will reread the parameters and change its display if it's
+  // appropriate.  Maybe later: mention which params have changed to save time.
+  virtual void refresh_ci () {}
+  // forces a vga update.  This was added so that a debugger can force
+  // a vga update when single stepping, without having to wait thousands
+  // of cycles for the normal vga refresh triggered by iodev/keyboard.cc.
+  virtual void refresh_vga () {}
+  // forces a call to bx_gui.handle_events.  This was added so that a debugger
+  // can force the gui events to be handled, so that interactive things such
+  // as a toolbar click will be processed.
+  virtual void handle_events () {}
+  // return first hard disk in ATA interface
+  virtual bx_param_c *get_first_cdrom () {return NULL;}
+  // return first cdrom in ATA interface
+  virtual bx_param_c *get_first_hd () {return NULL;}
+#if BX_DEBUGGER
+  // for debugger: same behavior as pressing control-C
+  virtual void debug_break () {}
+  virtual void debug_interpret_cmd (char *cmd) {}
+  virtual char *debug_get_next_command () {return NULL;}
+  virtual void debug_puts (const char *text) {}
+#endif
+  virtual void register_configuration_interface (
+    const char* name, 
+    config_interface_callback_t callback,
+    void *userdata) {}
+  virtual int configuration_interface(const char* name, ci_command_t command) {return -1; }
+  virtual int begin_simulation (int argc, char *argv[]) {return -1;}
+  typedef bool (*is_sim_thread_func_t)();
+  is_sim_thread_func_t is_sim_thread_func;
+  virtual void set_sim_thread_func (is_sim_thread_func_t func) {
+    is_sim_thread_func = func;
+  }
+  virtual bool is_sim_thread () {return true;}
+  virtual bool is_wx_selected () {return false;}
+  // provide interface to bx_gui->set_display_mode() method for config
+  // interfaces to use.
+  virtual void set_display_mode (disp_mode_t newmode) {}
+  virtual bool test_for_text_console () { return true; }
+};
+
+BOCHSAPI extern bx_simulator_interface_c *SIM;
+
+BOCHSAPI extern void bx_init_siminterface ();
+BOCHSAPI extern int bx_init_main (int argc, char *argv[]);
+
+#if defined(__WXMSW__) || defined(WIN32)
+// Just to provide HINSTANCE, etc. in files that have not included bochs.h.
+// I don't like this at all, but I don't see a way around it.
+#include <windows.h>
+#endif
+
+// define structure to hold data that is passed into our main function.
+typedef struct BOCHSAPI {
+  // standard argc,argv
+  int argc;
+  char **argv;
+#ifdef WIN32
+  char initial_dir[MAX_PATH];
+#endif
+#ifdef __WXMSW__
+  // these are only used when compiling with wxWindows.  This gives us a
+  // place to store the data that was passed to WinMain.
+  HINSTANCE hInstance;
+  HINSTANCE hPrevInstance;
+  LPSTR m_lpCmdLine;
+  int nCmdShow;
+#endif
+} bx_startup_flags_t;
+
+BOCHSAPI extern bx_startup_flags_t bx_startup_flags;
+BOCHSAPI extern bx_bool bx_user_quit;
diff --git a/tools/ioemu/gui/svga.cc b/tools/ioemu/gui/svga.cc
new file mode 100644 (file)
index 0000000..33020fc
--- /dev/null
@@ -0,0 +1,514 @@
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#define _MULTI_THREAD
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_WITH_SVGA
+
+#include <stdlib.h>
+#include </usr/include/vga.h>
+#include <vgagl.h>
+#include <vgakeyboard.h>
+#include <vgamouse.h>
+
+#include "font/vga.bitmap.h"
+//#include "icon_bochs.h"
+
+class bx_svga_gui_c : public bx_gui_c {
+public:
+  bx_svga_gui_c (void);
+  DECLARE_GUI_VIRTUAL_METHODS()
+  virtual void set_display_mode (disp_mode_t newmode);
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_svga_gui_c *theGui = NULL;
+
+IMPLEMENT_GUI_PLUGIN_CODE(svga)
+
+#define LOG_THIS theGui->
+
+static unsigned res_x, res_y;
+static int fontwidth = 8, fontheight = 16;
+static unsigned tilewidth, tileheight;
+static unsigned char vgafont[256 * 16];
+static int clut8 = 0;
+GraphicsContext *screen = NULL;
+static int save_vga_mode;
+static int save_vga_pal[256 * 3];
+
+void keyboard_handler(int scancode, int press);
+void mouse_handler(int button, int dx, int dy, int dz, 
+                   int drx, int dry, int drz);
+
+unsigned char reverse_byteorder(unsigned char b)
+{
+    unsigned char ret = 0;
+    
+    for (unsigned i=0;i<8;i++){
+       ret |= (b & 0x01) << (7 - i);
+       b >>= 1;
+    }
+    return ret;
+}
+
+void create_vga_font()
+{
+    memcpy(vgafont, bx_vgafont, sizeof(bx_vgafont));
+    
+    for (unsigned i=0;i< sizeof(bx_vgafont);i++) {
+       vgafont[i] = reverse_byteorder(vgafont[i]);
+    }    
+}
+
+bx_svga_gui_c::bx_svga_gui_c ()
+{
+  put("SVGA");
+}
+
+void bx_svga_gui_c::specific_init(
+    int argc,
+    char **argv,
+    unsigned x_tilesize,
+    unsigned y_tilesize,
+    unsigned header_bar_y)
+{
+  tilewidth = x_tilesize;
+  tileheight = y_tilesize;
+
+  if(vga_init() != 0 )
+  {
+    LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+    BX_PANIC (("Unable to initialize SVGAlib"));
+    return;
+  }
+  
+  screen = gl_allocatecontext();
+  
+  dimension_update(640,400);
+  create_vga_font();
+  gl_setfont(8, 16, (void *)vgafont);
+  gl_setwritemode(FONT_COMPRESSED);
+  
+  keyboard_init();
+  keyboard_seteventhandler((__keyboard_handler) keyboard_handler);
+
+  vga_setmousesupport(1);
+  mouse_seteventhandler((__mouse_handler) mouse_handler);
+  if (vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_FLAGS) & VGA_CLUT8) {
+    vga_ext_set(VGA_EXT_SET, VGA_CLUT8);
+    clut8 = 1;
+  }
+  // Save settings to prepare for mode transition in set_display_mode.
+  // If DISP_MODE_SIM is called first, these values will be used.
+  save_vga_mode = vga_getcurrentmode();
+  vga_getpalvec(0, 256, save_vga_pal);
+}
+
+void bx_svga_gui_c::text_update(
+    Bit8u *old_text,
+    Bit8u *new_text,
+    unsigned long cursor_x,
+    unsigned long cursor_y,
+    bx_vga_tminfo_t tm_info,
+    unsigned rows)
+{
+   unsigned x, y, i;
+   unsigned chars, cols;
+   char s[] = " ";
+   static unsigned int previ;
+   unsigned int cursori;
+   
+   cols = res_x/fontwidth;
+
+   cursori = (cursor_y*cols + cursor_x) * 2;
+   
+   chars = cols*rows;
+   
+   for (i=0; i<chars*2; i+=2) {
+        if (i == cursori || i == previ || old_text[i] != new_text[i] ||
+           old_text[i+1] != new_text[i+1]) {
+           
+       s[0] = new_text[i];
+       x = (i/2) % cols;
+       y = (i/2) / cols;
+
+       if (i == cursori) {
+           gl_setfontcolors(new_text[i+1] & 0x0F, (new_text[i+1] & 0xF0) >> 4);
+       } else {
+           gl_setfontcolors((new_text[i+1] & 0xF0) >> 4, new_text[i+1] & 0x0F);
+       }
+       gl_write(x * fontwidth, y * fontheight, s);
+       }
+    }
+    previ = cursori;
+}
+
+  int
+bx_svga_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+  return 0;
+}
+
+  int
+bx_svga_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+  return 0;
+}
+
+
+void bx_svga_gui_c::graphics_tile_update(
+    Bit8u *snapshot,
+    unsigned x,
+    unsigned y)
+{
+   gl_putbox(x, y, tilewidth, tileheight, snapshot);
+}
+
+static Bit32u vga_to_bx_key(int key)
+{
+    switch (key) {
+       case SCANCODE_ESCAPE: return BX_KEY_ESC;
+       case SCANCODE_1: return BX_KEY_1;
+       case SCANCODE_2: return BX_KEY_2;
+       case SCANCODE_3: return BX_KEY_3;
+       case SCANCODE_4: return BX_KEY_4;
+       case SCANCODE_5: return BX_KEY_5;
+       case SCANCODE_6: return BX_KEY_6;
+       case SCANCODE_7: return BX_KEY_7;
+       case SCANCODE_8: return BX_KEY_8;
+       case SCANCODE_9: return BX_KEY_9;
+       case SCANCODE_0: return BX_KEY_0;
+
+       case SCANCODE_MINUS: return BX_KEY_MINUS;
+       case SCANCODE_EQUAL: return BX_KEY_EQUALS;
+       case SCANCODE_TAB: return BX_KEY_TAB;
+       case SCANCODE_BACKSPACE: return BX_KEY_BACKSPACE;
+
+       case SCANCODE_Q: return BX_KEY_Q;
+       case SCANCODE_W: return BX_KEY_W;
+       case SCANCODE_E: return BX_KEY_E;
+       case SCANCODE_R: return BX_KEY_R;
+       case SCANCODE_T: return BX_KEY_T;
+       case SCANCODE_Y: return BX_KEY_Y;
+       case SCANCODE_U: return BX_KEY_U;
+       case SCANCODE_I: return BX_KEY_I;
+       case SCANCODE_O: return BX_KEY_O;
+       case SCANCODE_P: return BX_KEY_P;
+
+       case SCANCODE_BRACKET_LEFT: return BX_KEY_LEFT_BRACKET;
+       case SCANCODE_BRACKET_RIGHT: return BX_KEY_RIGHT_BRACKET;
+
+       case SCANCODE_ENTER: return BX_KEY_ENTER;
+       case SCANCODE_LEFTCONTROL: return BX_KEY_CTRL_L;
+
+       case SCANCODE_A: return BX_KEY_A;
+       case SCANCODE_S: return BX_KEY_S;
+       case SCANCODE_D: return BX_KEY_D;
+       case SCANCODE_F: return BX_KEY_F;
+       case SCANCODE_G: return BX_KEY_G;
+       case SCANCODE_H: return BX_KEY_H;
+       case SCANCODE_J: return BX_KEY_J;
+       case SCANCODE_K: return BX_KEY_K;
+       case SCANCODE_L: return BX_KEY_L;
+
+       case SCANCODE_SEMICOLON: return BX_KEY_SEMICOLON;
+       case SCANCODE_APOSTROPHE: return BX_KEY_SINGLE_QUOTE;
+       case SCANCODE_GRAVE: return BX_KEY_GRAVE;
+
+       case SCANCODE_LEFTSHIFT: return BX_KEY_SHIFT_L;
+       case SCANCODE_BACKSLASH: return BX_KEY_BACKSLASH;
+
+       case SCANCODE_Z: return BX_KEY_Z;
+       case SCANCODE_X: return BX_KEY_X;
+       case SCANCODE_C: return BX_KEY_C;
+       case SCANCODE_V: return BX_KEY_V;
+       case SCANCODE_B: return BX_KEY_B;
+       case SCANCODE_N: return BX_KEY_N;
+       case SCANCODE_M: return BX_KEY_M;
+
+       case SCANCODE_COMMA: return BX_KEY_COMMA;
+       case SCANCODE_PERIOD: return BX_KEY_PERIOD;
+       case SCANCODE_SLASH: return BX_KEY_SLASH;
+
+       case SCANCODE_RIGHTSHIFT: return BX_KEY_SHIFT_R;
+       case SCANCODE_KEYPADMULTIPLY: return BX_KEY_KP_MULTIPLY;
+       
+       case SCANCODE_LEFTALT: return BX_KEY_ALT_L;
+       case SCANCODE_SPACE: return BX_KEY_SPACE;
+       case SCANCODE_CAPSLOCK: return BX_KEY_CAPS_LOCK;
+
+       case SCANCODE_F1: return BX_KEY_F1;
+       case SCANCODE_F2: return BX_KEY_F2;
+       case SCANCODE_F3: return BX_KEY_F3;
+       case SCANCODE_F4: return BX_KEY_F4;
+       case SCANCODE_F5: return BX_KEY_F5;
+       case SCANCODE_F6: return BX_KEY_F6;
+       case SCANCODE_F7: return BX_KEY_F7;
+       case SCANCODE_F8: return BX_KEY_F8;
+       case SCANCODE_F9: return BX_KEY_F9;
+       case SCANCODE_F10: return BX_KEY_F10;
+
+       case SCANCODE_NUMLOCK: return BX_KEY_NUM_LOCK;
+       case SCANCODE_SCROLLLOCK: return BX_KEY_SCRL_LOCK;
+       
+       case SCANCODE_KEYPAD7: return BX_KEY_KP_HOME;
+       case SCANCODE_KEYPAD8: return BX_KEY_KP_UP;
+       case SCANCODE_KEYPAD9: return BX_KEY_KP_PAGE_UP;
+       case SCANCODE_KEYPADMINUS: return BX_KEY_KP_SUBTRACT;
+       case SCANCODE_KEYPAD4: return BX_KEY_KP_LEFT;
+       case SCANCODE_KEYPAD5: return BX_KEY_KP_5;
+       case SCANCODE_KEYPAD6: return BX_KEY_KP_RIGHT;
+       case SCANCODE_KEYPADPLUS: return BX_KEY_KP_ADD;
+       case SCANCODE_KEYPAD1: return BX_KEY_KP_END;
+       case SCANCODE_KEYPAD2: return BX_KEY_KP_DOWN;
+       case SCANCODE_KEYPAD3: return BX_KEY_KP_PAGE_DOWN;
+       case SCANCODE_KEYPAD0: return BX_KEY_KP_INSERT;
+//     case SCANCODE_KEYPADPERIOD: return BX_KEY_KP_; /* ??? */
+
+//     case SCANCODE_LESS: return BX_KEY_KP_LESS;      /* ??? */
+
+       case SCANCODE_F11: return BX_KEY_F11;
+       case SCANCODE_F12: return BX_KEY_F12;
+
+       case SCANCODE_KEYPADENTER: return BX_KEY_KP_ENTER;
+       case SCANCODE_RIGHTCONTROL: return BX_KEY_CTRL_R;
+       case SCANCODE_KEYPADDIVIDE: return BX_KEY_KP_DIVIDE;
+       case SCANCODE_PRINTSCREEN: return BX_KEY_PRINT;
+       case SCANCODE_RIGHTALT: return BX_KEY_ALT_R;
+       case SCANCODE_BREAK: return BX_KEY_PAUSE;
+
+       case SCANCODE_HOME: return BX_KEY_HOME;
+       case SCANCODE_CURSORBLOCKUP: return BX_KEY_UP;
+       case SCANCODE_PAGEUP: return BX_KEY_PAGE_UP;
+       case SCANCODE_CURSORBLOCKLEFT: return BX_KEY_LEFT;
+       case SCANCODE_CURSORBLOCKRIGHT: return BX_KEY_RIGHT;
+       case SCANCODE_END: return BX_KEY_END;
+       case SCANCODE_CURSORBLOCKDOWN: return BX_KEY_DOWN;
+       case SCANCODE_PAGEDOWN: return BX_KEY_PAGE_DOWN;
+       case SCANCODE_INSERT: return BX_KEY_INSERT;
+       case SCANCODE_REMOVE: return BX_KEY_DELETE;
+
+       case SCANCODE_RIGHTWIN: return BX_KEY_WIN_R;
+       case SCANCODE_LEFTWIN: return BX_KEY_WIN_L;
+
+       default: return 0;
+    }
+}
+
+void keyboard_handler(int scancode, int press)
+{
+    if (scancode != SCANCODE_F12) {
+       int bx_key = vga_to_bx_key(scancode);
+       Bit32u key_state;
+               
+       if (press) {
+           key_state = BX_KEY_PRESSED;
+       } else { 
+           key_state = BX_KEY_RELEASED;
+       }
+       
+       DEV_kbd_gen_scancode(bx_key | key_state);
+    } else {
+       BX_INFO(("F12 pressed"));
+       // show runtime options menu, which uses stdin/stdout   
+       SIM->configuration_interface (NULL, CI_RUNTIME_CONFIG);
+    }
+}
+
+void mouse_handler(int button, int dx, int dy, int dz, 
+                   int drx, int dry, int drz)
+{
+    int buttons = 0;
+
+    if (button & MOUSE_LEFTBUTTON) {
+       buttons |= 0x01;
+    }
+
+    if (button & MOUSE_RIGHTBUTTON) {
+       buttons |= 0x02;
+    }
+    DEV_mouse_motion((int) (0.25 * dx), (int) -(0.25 * dy), buttons);
+}
+
+void bx_svga_gui_c::handle_events(void)
+{
+    keyboard_update();
+    keyboard_clearstate();
+    mouse_update();
+}
+
+void bx_svga_gui_c::flush(void)
+{
+    gl_copyscreen(screen);
+}
+
+void bx_svga_gui_c::clear_screen(void)
+{
+    gl_clearscreen(0);
+}
+
+bx_bool bx_svga_gui_c::palette_change(
+    unsigned index,
+    unsigned red,
+    unsigned green,
+    unsigned blue)
+{
+  if( index > 255 ) return 0;
+
+  // without VGA_CLUT8 extension we have only 6 bits for each r,g,b value   
+  if (!clut8 && (red > 63 || green > 63 || blue > 63)) {
+       red   = red >> 2;
+       green = green >> 2;
+       blue  = blue >> 2;
+  }
+  
+  vga_setpalette(index, red, green, blue);
+  
+  return 1;
+}
+
+
+void bx_svga_gui_c::dimension_update(
+    unsigned x,
+    unsigned y,
+    unsigned fheight,
+    unsigned fwidth,
+    unsigned bpp)
+{
+  int newmode = 0;
+
+  if (bpp > 8) {
+    BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
+  }
+  if( fheight > 0 )
+  {
+    fontheight = fheight;
+    if (fwidth != 8) {
+      x = x * 8 / fwidth;
+    }
+    fontwidth = 8;
+  }
+
+  if( (x == res_x) && (y == res_y )) return;
+
+  if (x == 640 && y == 480) { 
+    newmode = G640x480x256;
+  } else if (x == 640 && y == 400) {
+    newmode = G640x400x256;
+  } else if (x == 320 && y == 200) {
+    newmode = G320x200x256;
+  }
+  
+  if (!vga_hasmode(newmode)) {
+    newmode = G640x480x256; // trying "default" mode...
+  }
+  
+  if (vga_setmode(newmode) != 0)
+  {
+      LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+      BX_PANIC (("Unable to set requested videomode: %ix%i", x, y));
+  }
+  
+  gl_setcontextvga(newmode);
+  gl_getcontext(screen);
+  gl_setcontextvgavirtual(newmode);
+  save_vga_mode = newmode;
+
+  res_x = x;
+  res_y = y;
+}
+
+
+unsigned bx_svga_gui_c::create_bitmap(
+    const unsigned char *bmap,
+    unsigned xdim,
+    unsigned ydim)
+{
+  return 0;
+}
+
+
+unsigned bx_svga_gui_c::headerbar_bitmap(
+    unsigned bmap_id,
+    unsigned alignment,
+    void (*f)(void))
+{
+  return 0;
+}
+
+
+void bx_svga_gui_c::replace_bitmap(
+    unsigned hbar_id,
+    unsigned bmap_id)
+{
+}
+
+
+void bx_svga_gui_c::show_headerbar(void)
+{
+}
+
+
+void bx_svga_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+
+
+void headerbar_click(int x)
+{
+}
+
+void bx_svga_gui_c::exit(void)
+{
+    vga_setmode(TEXT);
+    keyboard_close();
+    mouse_close();
+}
+
+void 
+bx_svga_gui_c::set_display_mode (disp_mode_t newmode)
+{
+  // if no mode change, do nothing.
+  if (disp_mode == newmode) return;
+  // remember the display mode for next time
+  disp_mode = newmode;
+  switch (newmode) {
+    case DISP_MODE_CONFIG:
+      BX_DEBUG (("switch to configuration mode (back to console)"));
+      // remember old values and switch to text mode
+      save_vga_mode = vga_getcurrentmode();
+      vga_getpalvec(0, 256, save_vga_pal);
+      keyboard_close();
+      vga_setmode(TEXT);
+      break;
+    case DISP_MODE_SIM:
+      BX_DEBUG (("switch to simulation mode (fullscreen)"));
+      keyboard_init();
+      keyboard_seteventhandler((__keyboard_handler) keyboard_handler);
+      vga_setmode(save_vga_mode);
+      vga_setpalvec(0, 256, save_vga_pal);
+      break;
+  }
+}
+
+#endif /* if BX_WITH_SVGA */
diff --git a/tools/ioemu/gui/term.cc b/tools/ioemu/gui/term.cc
new file mode 100644 (file)
index 0000000..37bf9c5
--- /dev/null
@@ -0,0 +1,843 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: term.cc,v 1.31 2003/08/17 23:40:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2000  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_WITH_TERM
+
+#include "icon_bochs.h"
+
+extern "C" {
+#include <curses.h>
+#include <signal.h>
+};
+
+class bx_term_gui_c : public bx_gui_c {
+public:
+  bx_term_gui_c (void) {}
+  DECLARE_GUI_VIRTUAL_METHODS()
+
+  virtual Bit32u get_sighandler_mask ();
+  // called when registered signal arrives
+  virtual void sighandler (int sig);
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_term_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(term)
+
+#define LOG_THIS theGui->
+
+bx_bool initialized = 0;
+static unsigned int text_cols = 80, text_rows = 25;
+
+static short curses_color[8] = {
+  /* 0 */ COLOR_BLACK,
+  /* 1 */ COLOR_BLUE,
+  /* 2 */ COLOR_GREEN,
+  /* 3 */ COLOR_CYAN,
+  /* 4 */ COLOR_RED,
+  /* 5 */ COLOR_MAGENTA,
+  /* 6 */ COLOR_YELLOW,
+  /* 7 */ COLOR_WHITE
+};
+
+static chtype vga_to_term[128] = {
+  0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7,
+  0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5,
+  0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9,
+  0xff, 0xd6, 0xdc, 0xe7, 0xa3, 0xa5, ' ',  ' ',
+  0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba,
+  0xbf, ' ',  0xac, ' ',  ' ',  0xa1, 0xab, 0xbb,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, ' ',  ' ',  ' ',  ' ',
+  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  0xb5, ' ',
+  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',  ' ',
+  ' ',  0xb1, ' ',  ' ',  ' ',  ' ',  0xf7, ' ',
+  0xb0, ' ',  ' ',  ' ',  ' ',  0xb2, ' ',  ' '
+};
+
+static void
+do_scan(int key_event, int shift, int ctrl, int alt)
+{
+       /* XXX At some point, cache alt/ctrl/shift so only when the state
+                changes do we simulate a press or release, to cut down on
+                keyboard input to the simulated machine */
+
+       BX_DEBUG(("key_event %d/0x%x %s%s%s",
+                 key_event,key_event,
+                 shift?"(shift)":"",
+                 ctrl?"(ctrl)":"",
+                 alt?"(alt)":""));
+       if(shift)
+               DEV_kbd_gen_scancode(BX_KEY_SHIFT_L);
+       if(ctrl)
+               DEV_kbd_gen_scancode(BX_KEY_CTRL_L);
+       if(alt)
+               DEV_kbd_gen_scancode(BX_KEY_ALT_L);
+       DEV_kbd_gen_scancode(key_event);
+       key_event |= BX_KEY_RELEASED;
+
+       DEV_kbd_gen_scancode(key_event);
+       if(alt)
+               DEV_kbd_gen_scancode(BX_KEY_ALT_L|BX_KEY_RELEASED);
+       if(ctrl)
+               DEV_kbd_gen_scancode(BX_KEY_CTRL_L|BX_KEY_RELEASED);
+       if(shift)
+               DEV_kbd_gen_scancode(BX_KEY_SHIFT_L|BX_KEY_RELEASED);
+}
+
+Bit32u 
+bx_term_gui_c::get_sighandler_mask ()
+{
+  return 
+    (1<<SIGHUP)
+    | (1<<SIGINT)
+    | (1<<SIGQUIT)
+#ifdef SIGSTOP
+    | (1<<SIGSTOP)
+#endif
+#ifdef SIGTSTP
+    | (1<<SIGTSTP)
+#endif
+    | (1<<SIGTERM);
+}
+
+void
+bx_term_gui_c::sighandler(int signo)
+{
+       switch(signo) {
+       case SIGINT:
+               do_scan(BX_KEY_C,0,1,0);
+               break;
+#ifdef SIGSTOP
+       case SIGSTOP:
+               do_scan(BX_KEY_S,0,1,0);
+               break;
+#endif
+#ifdef SIGTSTP
+       case SIGTSTP:
+               do_scan(BX_KEY_Z,0,1,0);
+               break;
+#endif
+       default:
+               BX_INFO(("sig %d caught",signo));
+               break;
+       }
+}
+
+// ::SPECIFIC_INIT()
+//
+// Called from gui.cc, once upon program startup, to allow for the
+// specific GUI code (X11, BeOS, ...) to be initialized.
+//
+// argc, argv: not used right now, but the intention is to pass native GUI
+//     specific options from the command line.  (X11 options, BeOS options,...)
+//
+// tilewidth, tileheight: for optimization, graphics_tile_update() passes
+//     only updated regions of the screen to the gui code to be redrawn.
+//     These define the dimensions of a region (tile).
+// headerbar_y:  A headerbar (toolbar) is display on the top of the
+//     VGA window, showing floppy status, and other information.  It
+//     always assumes the width of the current VGA mode width, but
+//     it's height is defined by this parameter.
+
+       void
+bx_term_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+       unsigned headerbar_y)
+{
+       put("TGUI");
+       UNUSED(argc);
+       UNUSED(argv);
+       UNUSED(tilewidth);
+       UNUSED(tileheight);
+       UNUSED(headerbar_y);
+
+       UNUSED(bochs_icon_bits);  // global variable
+
+       // the ask menu causes trouble
+       io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
+       // logfile should be different from stderr, otherwise terminal mode
+       // really ends up having fun
+       if (!strcmp(bx_options.log.Ofilename->getptr(), "-"))
+               BX_PANIC(("cannot log to stderr in term mode"));
+
+       initscr();
+       start_color();
+       cbreak();
+       curs_set(2);
+       keypad(stdscr,TRUE);
+       nodelay(stdscr, TRUE);
+       noecho();
+
+#if BX_HAVE_COLOR_SET
+       if (has_colors()) {
+               for (int i=0; i<COLORS; i++) {
+                       for (int j=0; j<COLORS; j++) {
+                               if ((i!=0)||(j!=0)) init_pair(i * COLORS + j, j, i);
+                       }
+               }
+       }
+#endif
+
+       if (bx_options.Oprivate_colormap->get ())
+               BX_ERROR(("WARNING: private_colormap option ignored."));
+       initialized = 1;
+}
+
+
+
+void
+do_char(int character,int alt)
+{
+       switch (character) {
+       // control keys
+       case   0x9: do_scan(BX_KEY_TAB,0,0,alt); break;
+       case   0xa: do_scan(BX_KEY_KP_ENTER,0,0,alt); break;
+       case   0xd: do_scan(BX_KEY_KP_DELETE,0,0,alt); break;
+       case   0x1: do_scan(BX_KEY_A,0,1,alt); break;
+       case   0x2: do_scan(BX_KEY_B,0,1,alt); break;
+       case   0x3: do_scan(BX_KEY_C,0,1,alt); break;
+       case   0x4: do_scan(BX_KEY_D,0,1,alt); break;
+       case   0x5: do_scan(BX_KEY_E,0,1,alt); break;
+       case   0x6: do_scan(BX_KEY_F,0,1,alt); break;
+       case   0x7: do_scan(BX_KEY_G,0,1,alt); break;
+       case   0x8: do_scan(BX_KEY_H,0,1,alt); break;
+       case   0xb: do_scan(BX_KEY_K,0,1,alt); break;
+       case   0xc: do_scan(BX_KEY_L,0,1,alt); break;
+       case   0xe: do_scan(BX_KEY_N,0,1,alt); break;
+       case   0xf: do_scan(BX_KEY_O,0,1,alt); break;
+       case  0x10: do_scan(BX_KEY_P,0,1,alt); break;
+       case  0x11: do_scan(BX_KEY_Q,0,1,alt); break;
+       case  0x12: do_scan(BX_KEY_R,0,1,alt); break;
+       case  0x13: do_scan(BX_KEY_S,0,1,alt); break;
+       case  0x14: do_scan(BX_KEY_T,0,1,alt); break;
+       case  0x15: do_scan(BX_KEY_U,0,1,alt); break;
+       case  0x16: do_scan(BX_KEY_V,0,1,alt); break;
+       case  0x17: do_scan(BX_KEY_W,0,1,alt); break;
+       case  0x18: do_scan(BX_KEY_X,0,1,alt); break;
+       case  0x19: do_scan(BX_KEY_Y,0,1,alt); break;
+       case  0x1a: do_scan(BX_KEY_Z,0,1,alt); break;
+       case  0x20: do_scan(BX_KEY_SPACE,0,0,alt); break;
+       case 0x107: do_scan(BX_KEY_BACKSPACE,0,0,alt); break;
+       case 0x102: do_scan(BX_KEY_DOWN,0,0,alt); break;
+       case 0x103: do_scan(BX_KEY_UP,0,0,alt); break;
+       case 0x104: do_scan(BX_KEY_LEFT,0,0,alt); break;
+       case 0x105: do_scan(BX_KEY_RIGHT,0,0,alt); break;
+       case 0x152: do_scan(BX_KEY_PAGE_DOWN,0,0,alt); break;
+       case 0x153: do_scan(BX_KEY_PAGE_UP,0,0,alt); break;
+       case 0x106: do_scan(BX_KEY_HOME,0,0,alt); break;
+       case 0x168: do_scan(BX_KEY_END,0,0,alt); break;
+       case 0x14b: do_scan(BX_KEY_INSERT,0,0,alt); break;
+       case 0x7f:  do_scan(BX_KEY_DELETE,0,0,alt); break;
+       case 0x1b:  do_scan(BX_KEY_ESC,0,0,alt); break;
+       case '!': do_scan(BX_KEY_1,1,0,alt); break;
+       case '\'': do_scan(BX_KEY_SINGLE_QUOTE,0,0,alt); break;
+       case '#': do_scan(BX_KEY_3,1,0,alt); break;
+       case '$': do_scan(BX_KEY_4,1,0,alt); break;
+       case '%': do_scan(BX_KEY_5,1,0,alt); break;
+       case '^': do_scan(BX_KEY_6,1,0,alt); break;
+       case '&': do_scan(BX_KEY_7,1,0,alt); break;
+       case '"': do_scan(BX_KEY_SINGLE_QUOTE,1,0,alt); break;
+
+       // ()*+,-./
+       case '(': do_scan(BX_KEY_9,1,0,alt); break;
+       case ')': do_scan(BX_KEY_0,1,0,alt); break;
+       case '*': do_scan(BX_KEY_8,1,0,alt); break;
+       case '+': do_scan(BX_KEY_EQUALS,1,0,alt); break;
+       case ',': do_scan(BX_KEY_COMMA,0,0,alt); break;
+       case '-': do_scan(BX_KEY_MINUS,0,0,alt); break;
+       case '.': do_scan(BX_KEY_PERIOD,0,0,alt); break;
+       case '/': do_scan(BX_KEY_SLASH,0,0,alt); break;
+
+       // 01234567
+       case '0': do_scan(BX_KEY_0,0,0,alt); break;
+       case '1': do_scan(BX_KEY_1,0,0,alt); break;
+       case '2': do_scan(BX_KEY_2,0,0,alt); break;
+       case '3': do_scan(BX_KEY_3,0,0,alt); break;
+       case '4': do_scan(BX_KEY_4,0,0,alt); break;
+       case '5': do_scan(BX_KEY_5,0,0,alt); break;
+       case '6': do_scan(BX_KEY_6,0,0,alt); break;
+       case '7': do_scan(BX_KEY_7,0,0,alt); break;
+
+       // 89:;<=>?
+       case '8': do_scan(BX_KEY_8,0,0,alt); break;
+       case '9': do_scan(BX_KEY_9,0,0,alt); break;
+       case ':': do_scan(BX_KEY_SEMICOLON,1,0,alt); break;
+       case ';': do_scan(BX_KEY_SEMICOLON,0,0,alt); break;
+       case '<': do_scan(BX_KEY_COMMA,1,0,alt); break;
+       case '=': do_scan(BX_KEY_EQUALS,0,0,alt); break;
+       case '>': do_scan(BX_KEY_PERIOD,1,0,alt); break;
+       case '?': do_scan(BX_KEY_SLASH,1,0,alt); break;
+
+       // @ABCDEFG
+       case '@': do_scan(BX_KEY_2,1,0,alt); break;
+       case 'A': do_scan(BX_KEY_A,1,0,alt); break;
+       case 'B': do_scan(BX_KEY_B,1,0,alt); break;
+       case 'C': do_scan(BX_KEY_C,1,0,alt); break;
+       case 'D': do_scan(BX_KEY_D,1,0,alt); break;
+       case 'E': do_scan(BX_KEY_E,1,0,alt); break;
+       case 'F': do_scan(BX_KEY_F,1,0,alt); break;
+       case 'G': do_scan(BX_KEY_G,1,0,alt); break;
+
+
+       // HIJKLMNO
+       case 'H': do_scan(BX_KEY_H,1,0,alt); break;
+       case 'I': do_scan(BX_KEY_I,1,0,alt); break;
+       case 'J': do_scan(BX_KEY_J,1,0,alt); break;
+       case 'K': do_scan(BX_KEY_K,1,0,alt); break;
+       case 'L': do_scan(BX_KEY_L,1,0,alt); break;
+       case 'M': do_scan(BX_KEY_M,1,0,alt); break;
+       case 'N': do_scan(BX_KEY_N,1,0,alt); break;
+       case 'O': do_scan(BX_KEY_O,1,0,alt); break;
+
+
+       // PQRSTUVW
+       case 'P': do_scan(BX_KEY_P,1,0,alt); break;
+       case 'Q': do_scan(BX_KEY_Q,1,0,alt); break;
+       case 'R': do_scan(BX_KEY_R,1,0,alt); break;
+       case 'S': do_scan(BX_KEY_S,1,0,alt); break;
+       case 'T': do_scan(BX_KEY_T,1,0,alt); break;
+       case 'U': do_scan(BX_KEY_U,1,0,alt); break;
+       case 'V': do_scan(BX_KEY_V,1,0,alt); break;
+       case 'W': do_scan(BX_KEY_W,1,0,alt); break;
+
+       // XYZ[\]^_
+       case 'X': do_scan(BX_KEY_X,1,0,alt); break;
+       case 'Y': do_scan(BX_KEY_Y,1,0,alt); break;
+       case 'Z': do_scan(BX_KEY_Z,1,0,alt); break;
+       case '{': do_scan(BX_KEY_LEFT_BRACKET,1,0,alt); break;
+       case '|': do_scan(BX_KEY_BACKSLASH,1,0,alt); break;
+       case '}': do_scan(BX_KEY_RIGHT_BRACKET,1,0,alt); break;
+       case '_': do_scan(BX_KEY_MINUS,1,0,alt); break;
+
+       // `abcdefg
+       case '`': do_scan(BX_KEY_GRAVE,0,0,alt); break;
+       case 'a': do_scan(BX_KEY_A,0,0,alt); break;
+       case 'b': do_scan(BX_KEY_B,0,0,alt); break;
+       case 'c': do_scan(BX_KEY_C,0,0,alt); break;
+       case 'd': do_scan(BX_KEY_D,0,0,alt); break;
+       case 'e': do_scan(BX_KEY_E,0,0,alt); break;
+       case 'f': do_scan(BX_KEY_F,0,0,alt); break;
+       case 'g': do_scan(BX_KEY_G,0,0,alt); break;
+
+       // hijklmno
+       case 'h': do_scan(BX_KEY_H,0,0,alt); break;
+       case 'i': do_scan(BX_KEY_I,0,0,alt); break;
+       case 'j': do_scan(BX_KEY_J,0,0,alt); break;
+       case 'k': do_scan(BX_KEY_K,0,0,alt); break;
+       case 'l': do_scan(BX_KEY_L,0,0,alt); break;
+       case 'm': do_scan(BX_KEY_M,0,0,alt); break;
+       case 'n': do_scan(BX_KEY_N,0,0,alt); break;
+       case 'o': do_scan(BX_KEY_O,0,0,alt); break;
+
+       // pqrstuvw
+       case 'p': do_scan(BX_KEY_P,0,0,alt); break;
+       case 'q': do_scan(BX_KEY_Q,0,0,alt); break;
+       case 'r': do_scan(BX_KEY_R,0,0,alt); break;
+       case 's': do_scan(BX_KEY_S,0,0,alt); break;
+       case 't': do_scan(BX_KEY_T,0,0,alt); break;
+       case 'u': do_scan(BX_KEY_U,0,0,alt); break;
+       case 'v': do_scan(BX_KEY_V,0,0,alt); break;
+       case 'w': do_scan(BX_KEY_W,0,0,alt); break;
+
+       // xyz{|}~
+       case 'x': do_scan(BX_KEY_X,0,0,alt); break;
+       case 'y': do_scan(BX_KEY_Y,0,0,alt); break;
+       case 'z': do_scan(BX_KEY_Z,0,0,alt); break;
+       case '[': do_scan(BX_KEY_LEFT_BRACKET,0,0,alt); break;
+       case '\\': do_scan(BX_KEY_BACKSLASH,0,0,alt); break;
+       case ']': do_scan(BX_KEY_RIGHT_BRACKET,0,0,alt); break;
+       case '~': do_scan(BX_KEY_GRAVE,1,0,alt); break;
+
+       // function keys
+       case KEY_F(1): do_scan(BX_KEY_F1,0,0,alt); break;
+       case KEY_F(2): do_scan(BX_KEY_F2,0,0,alt); break;
+       case KEY_F(3): do_scan(BX_KEY_F3,0,0,alt); break;
+       case KEY_F(4): do_scan(BX_KEY_F4,0,0,alt); break;
+       case KEY_F(5): do_scan(BX_KEY_F5,0,0,alt); break;
+       case KEY_F(6): do_scan(BX_KEY_F6,0,0,alt); break;
+       case KEY_F(7): do_scan(BX_KEY_F7,0,0,alt); break;
+       case KEY_F(8): do_scan(BX_KEY_F8,0,0,alt); break;
+       case KEY_F(9): do_scan(BX_KEY_F9,0,0,alt); break;
+       case KEY_F(10): do_scan(BX_KEY_F10,0,0,alt); break;
+       case KEY_F(11): do_scan(BX_KEY_F11,0,0,alt); break;
+       case KEY_F(12): do_scan(BX_KEY_F12,0,0,alt); break;
+
+       // shifted function keys
+       case KEY_F(13): do_scan(BX_KEY_F1,1,0,alt); break;
+       case KEY_F(14): do_scan(BX_KEY_F2,1,0,alt); break;
+       case KEY_F(15): do_scan(BX_KEY_F3,1,0,alt); break;
+       case KEY_F(16): do_scan(BX_KEY_F4,1,0,alt); break;
+       case KEY_F(17): do_scan(BX_KEY_F5,1,0,alt); break;
+       case KEY_F(18): do_scan(BX_KEY_F6,1,0,alt); break;
+       case KEY_F(19): do_scan(BX_KEY_F7,1,0,alt); break;
+       case KEY_F(20): do_scan(BX_KEY_F8,1,0,alt); break;
+
+       default:
+               if(character > 0x79) {
+                       do_char(character - 0x80,1);
+                       break;
+               }
+
+               BX_INFO(("character unhandled: 0x%x",character));
+               break;
+       }
+}
+
+
+// ::HANDLE_EVENTS()
+//
+// Called periodically (vga_update_interval in .bochsrc) so the
+// the gui code can poll for keyboard, mouse, and other
+// relevant events.
+
+       void
+bx_term_gui_c::handle_events(void)
+{
+       int character;
+       while((character = getch()) != ERR) {
+               BX_DEBUG(("scancode(0x%x)",character));
+               do_char(character,0);
+       }
+}
+
+
+
+// ::FLUSH()
+//
+// Called periodically, requesting that the gui code flush all pending
+// screen update requests.
+
+       void
+bx_term_gui_c::flush(void)
+{
+       if (initialized)
+         refresh();
+}
+
+
+// ::CLEAR_SCREEN()
+//
+// Called to request that the VGA region is cleared.  Don't
+// clear the area that defines the headerbar.
+
+       void
+bx_term_gui_c::clear_screen(void)
+{
+  clear();
+#if BX_HAVE_COLOR_SET
+  color_set(7, NULL);
+#endif
+#if BX_HAVE_MVHLINE
+  if (LINES > (int)text_rows) {
+    mvhline(text_rows, 0, ACS_HLINE, text_cols);
+  }
+#endif
+#if BX_HAVE_MVVLINE
+  if (COLS > (int)text_cols) {
+    mvvline(0, text_cols, ACS_VLINE, text_rows);
+  }
+#endif
+  if ((LINES > (int)text_rows) && (COLS > (int)text_cols)) {
+    mvaddch(text_rows, text_cols, ACS_LRCORNER);
+  }
+}
+
+int
+get_color_pair(Bit8u vga_attr)
+{
+       int term_attr;
+
+       term_attr = curses_color[vga_attr & 0x07];
+       term_attr |= (curses_color[(vga_attr & 0x70) >> 4] << 3);
+       return term_attr;
+}
+
+chtype
+get_term_char(Bit8u vga_char[])
+{
+  int term_char;
+
+  if ((vga_char[1] & 0x0f) == ((vga_char[1] >> 4) & 0x0f)) {
+    return ' ';
+  }
+  switch (vga_char[0]) {
+    case 0x04: term_char = ACS_DIAMOND; break;
+    case 0x18: term_char = ACS_UARROW; break;
+    case 0x19: term_char = ACS_DARROW; break;
+    case 0x1a: term_char = ACS_RARROW; break;
+    case 0x1b: term_char = ACS_LARROW; break;
+    case 0xc4:
+    case 0xcd: term_char = ACS_HLINE; break;
+    case 0xb3:
+    case 0xba: term_char = ACS_VLINE; break;
+    case 0xc9:
+    case 0xd5:
+    case 0xd6:
+    case 0xda: term_char = ACS_ULCORNER; break;
+    case 0xb7:
+    case 0xb8:
+    case 0xbb:
+    case 0xbf: term_char = ACS_URCORNER; break;
+    case 0xc0:
+    case 0xc8:
+    case 0xd3:
+    case 0xd4: term_char = ACS_LLCORNER; break;
+    case 0xbc:
+    case 0xbd:
+    case 0xbe:
+    case 0xd9: term_char = ACS_LRCORNER; break;
+    case 0xc3:
+    case 0xc6:
+    case 0xc7:
+    case 0xcc: term_char = ACS_LTEE; break;
+    case 0xb4:
+    case 0xb5:
+    case 0xb6:
+    case 0xb9: term_char = ACS_RTEE; break;
+    case 0xc2:
+    case 0xcb:
+    case 0xd1:
+    case 0xd2: term_char = ACS_TTEE; break;
+    case 0xc1:
+    case 0xca:
+    case 0xcf:
+    case 0xd0: term_char = ACS_BTEE; break;
+    case 0xc5:
+    case 0xce:
+    case 0xd7:
+    case 0xd8: term_char = ACS_PLUS; break;
+    case 0xb0:
+    case 0xb1: term_char = ACS_CKBOARD; break;
+    case 0xb2: term_char = ACS_BOARD; break;
+    case 0xdb: term_char = ACS_BLOCK; break;
+    default:
+      if (vga_char[0] > 0x7f) {
+        term_char = vga_to_term[vga_char[0]-0x80];
+      } else if (vga_char[0] > 0x1f) {
+        term_char = vga_char[0];
+      } else {
+        term_char = ' ';
+      }
+  }
+  return term_char;
+}
+
+// ::TEXT_UPDATE()
+//
+// Called in a VGA text mode, to update the screen with
+// new content.
+//
+// old_text: array of character/attributes making up the contents
+//           of the screen from the last call.  See below
+// new_text: array of character/attributes making up the current
+//           contents, which should now be displayed.  See below
+//
+// format of old_text & new_text: each is 4000 bytes long.
+//     This represents 80 characters wide by 25 high, with
+//     each character being 2 bytes.  The first by is the
+//     character value, the second is the attribute byte.
+//     I currently don't handle the attribute byte.
+//
+// cursor_x: new x location of cursor
+// cursor_y: new y location of cursor
+
+       void
+bx_term_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+       unsigned long cursor_x, unsigned long cursor_y,
+       bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+  unsigned char *old_line, *new_line, *new_start;
+  unsigned char cAttr;
+  unsigned int hchars, rows, x, y;
+  chtype ch;
+  bx_bool force_update = 0;
+
+  UNUSED(nrows);
+
+  if(charmap_updated) {
+    force_update = 1;
+    charmap_updated = 0;
+  }
+
+  new_start = new_text;
+  rows = text_rows;
+  y = 0;
+  do {
+    hchars = text_cols;
+    new_line = new_text;
+    old_line = old_text;
+    x = 0;
+    do {
+      if (force_update || (old_text[0] != new_text[0])
+          || (old_text[1] != new_text[1])) {
+#if BX_HAVE_COLOR_SET
+        if (has_colors()) {
+          color_set(get_color_pair(new_text[1]), NULL);
+        }
+#endif
+        ch = get_term_char(&new_text[0]);
+        if ((new_text[1] & 0x08) > 0) ch |= A_BOLD;
+        if ((new_text[1] & 0x80) > 0) ch |= A_BLINK;
+        mvaddch(y, x, ch);
+      }
+      x++;
+      new_text+=2;
+      old_text+=2;
+    } while (--hchars);
+    y++;
+    new_text = new_line + tm_info.line_offset;
+    old_text = old_line + tm_info.line_offset;
+  } while (--rows);
+
+  if ((cursor_x<text_cols) && (cursor_y<text_rows)
+      && (tm_info.cs_start <= tm_info.cs_end)) {
+    if(cursor_x>0)
+      cursor_x--;
+    else {
+      cursor_x=COLS-1;
+      cursor_y--;
+    }
+    cAttr = new_start[cursor_y*tm_info.line_offset+cursor_x*2+1];
+#if BX_HAVE_COLOR_SET
+    if (has_colors()) {
+      color_set(get_color_pair(cAttr), NULL);
+    }
+#endif
+    ch = get_term_char(&new_start[cursor_y*tm_info.line_offset+cursor_x*2]);
+    if ((cAttr & 0x08) > 0) ch |= A_BOLD;
+    if ((cAttr & 0x80) > 0) ch |= A_REVERSE;
+    mvaddch(cursor_y, cursor_x, ch);
+    curs_set(2);
+  } else {
+    curs_set(0);
+  }
+}
+
+  int
+bx_term_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+  return 0;
+}
+
+  int
+bx_term_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+  return 0;
+}
+
+
+// ::PALETTE_CHANGE()
+//
+// Allocate a color in the native GUI, for this color, and put
+// it in the colormap location 'index'.
+// returns: 0=no screen update needed (color map change has direct effect)
+//          1=screen updated needed (redraw using current colormap)
+
+       bx_bool
+bx_term_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+       BX_DEBUG(("color pallete request (%d,%d,%d,%d) ignored",
+                 index,red,green,blue));
+       return(0);
+}
+
+
+// ::GRAPHICS_TILE_UPDATE()
+//
+// Called to request that a tile of graphics be drawn to the
+// screen, since info in this region has changed.
+//
+// tile: array of 8bit values representing a block of pixels with
+//       dimension equal to the 'tilewidth' & 'tileheight' parameters to
+//       ::specific_init().  Each value specifies an index into the
+//       array of colors you allocated for ::palette_change()
+// x0: x origin of tile
+// y0: y origin of tile
+//
+// note: origin of tile and of window based on (0,0) being in the upper
+//       left of the window.
+
+       void
+bx_term_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+       UNUSED(tile);
+       UNUSED(x0);
+       UNUSED(y0);
+}
+
+
+
+// ::DIMENSION_UPDATE()
+//
+// Called when the VGA mode changes it's X,Y dimensions.
+// Resize the window to this size, but you need to add on
+// the height of the headerbar to the Y value.
+//
+// x: new VGA x size
+// y: new VGA y size (add headerbar_y parameter from ::specific_init().
+// fheight: new VGA character height in text mode
+// fwidth : new VGA character width in text mode
+// bpp : bits per pixel in graphics mode
+
+       void
+bx_term_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+  if (bpp > 8) {
+    BX_PANIC(("%d bpp graphics mode not supported", bpp));
+  }
+  if (fheight > 0) {
+    text_cols = x / fwidth;
+    text_rows = y / fheight;
+#if BX_HAVE_COLOR_SET
+    color_set(7, NULL);
+#endif
+#if BX_HAVE_MVHLINE
+    if (LINES > (int)text_rows) {
+      mvhline(text_rows, 0, ACS_HLINE, text_cols);
+    }
+#endif
+#if BX_HAVE_MVVLINE
+    if (COLS > (int)text_cols) {
+      mvvline(0, text_cols, ACS_VLINE, text_rows);
+    }
+#endif
+    if ((LINES > (int)text_rows) && (COLS > (int)text_cols)) {
+      mvaddch(text_rows, text_cols, ACS_LRCORNER);
+    }
+  }
+}
+
+
+// ::CREATE_BITMAP()
+//
+// Create a monochrome bitmap of size 'xdim' by 'ydim', which will
+// be drawn in the headerbar.  Return an integer ID to the bitmap,
+// with which the bitmap can be referenced later.
+//
+// bmap: packed 8 pixels-per-byte bitmap.  The pixel order is:
+//       bit0 is the left most pixel, bit7 is the right most pixel.
+// xdim: x dimension of bitmap
+// ydim: y dimension of bitmap
+
+       unsigned
+bx_term_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+       UNUSED(bmap);
+       UNUSED(xdim);
+       UNUSED(ydim);
+       return(0);
+}
+
+
+// ::HEADERBAR_BITMAP()
+//
+// Called to install a bitmap in the bochs headerbar (toolbar).
+//
+// bmap_id: will correspond to an ID returned from
+//     ::create_bitmap().  'alignment' is either BX_GRAVITY_LEFT
+//     or BX_GRAVITY_RIGHT, meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// alignment: is either BX_GRAVITY_LEFT or BX_GRAVITY_RIGHT,
+//     meaning install the bitmap in the next
+//     available leftmost or rightmost space.
+// f: a 'C' function pointer to callback when the mouse is clicked in
+//     the boundaries of this bitmap.
+
+       unsigned
+bx_term_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+       UNUSED(bmap_id);
+       UNUSED(alignment);
+       UNUSED(f);
+       return(0);
+}
+
+
+// ::SHOW_HEADERBAR()
+//
+// Show (redraw) the current headerbar, which is composed of
+// currently installed bitmaps.
+
+       void
+bx_term_gui_c::show_headerbar(void)
+{
+}
+
+
+// ::REPLACE_BITMAP()
+//
+// Replace the bitmap installed in the headerbar ID slot 'hbar_id',
+// with the one specified by 'bmap_id'.  'bmap_id' will have
+// been generated by ::create_bitmap().  The old and new bitmap
+// must be of the same size.  This allows the bitmap the user
+// sees to change, when some action occurs.  For example when
+// the user presses on the floppy icon, it then displays
+// the ejected status.
+//
+// hbar_id: headerbar slot ID
+// bmap_id: bitmap ID
+
+       void
+bx_term_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+       UNUSED(hbar_id);
+       UNUSED(bmap_id);
+}
+
+
+// ::EXIT()
+//
+// Called before bochs terminates, to allow for a graceful
+// exit from the native GUI mechanism.
+
+       void
+bx_term_gui_c::exit(void)
+{
+       if (!initialized) return;
+       clear();
+       flush();
+       endwin();
+       BX_DEBUG(("exiting"));
+}
+
+  void
+bx_term_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+}
+#endif /* if BX_WITH_TERM */
diff --git a/tools/ioemu/gui/textconfig.cc b/tools/ioemu/gui/textconfig.cc
new file mode 100644 (file)
index 0000000..7b5b098
--- /dev/null
@@ -0,0 +1,995 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: textconfig.cc,v 1.18 2003/10/24 15:39:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This is code for a text-mode configuration interface.  Note that this file
+// does NOT include bochs.h.  Instead, it does all of its contact with
+// the simulator through an object called SIM, defined in siminterface.cc
+// and siminterface.h.  This separation adds an extra layer of method
+// calls before any work can be done, but the benefit is that the compiler
+// enforces the rules.  I can guarantee that textconfig.cc doesn't call any
+// I/O device objects directly, for example, because the bx_devices symbol
+// isn't even defined in this context.
+//
+
+#include "config.h"
+
+extern "C" {
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+}
+#include "osdep.h"
+#include "textconfig.h"
+#include "siminterface.h"
+#include "extplugin.h"
+#ifdef WIN32
+#include "win32dialog.h"
+#endif
+
+#define CI_PATH_LENGTH 512
+
+#define BX_INSERTED 11
+
+/* functions for changing particular options */
+void bx_config_interface_init ();
+int bx_read_rc (char *rc);
+int bx_write_rc (char *rc);
+void bx_log_options (int individual);
+
+/******************************************************************/
+/* lots of code stolen from bximage.c */
+/* remove leading spaces, newline junk at end.  returns pointer to 
+ cleaned string, which is between s0 and the null */
+char *
+clean_string (char *s0)
+{
+  char *s = s0;
+  char *ptr;
+  /* find first nonblank */
+  while (isspace (*s))
+    s++;
+  /* truncate string at first non-alphanumeric */
+  ptr = s;
+  while (isprint (*ptr))
+    ptr++;
+  *ptr = 0;
+  return s;
+}
+
+void
+double_percent (char *s, int max_len)
+{
+  char d[CI_PATH_LENGTH];
+  int  i=0,j=0;
+
+  if (max_len>CI_PATH_LENGTH)
+    max_len=CI_PATH_LENGTH;
+
+  max_len--;
+
+  while((s[i]!=0)&&(j<max_len))
+  {
+    d[j++]=s[i];
+    if((s[i]=='%')&&(j<max_len))
+    {
+      d[j++]=s[i];
+    }
+    i++;
+  }
+  d[j]=0;
+  strcpy(s,d);
+}
+
+/* returns 0 on success, -1 on failure.  The value goes into out. */
+int 
+ask_uint (char *prompt, Bit32u min, Bit32u max, Bit32u the_default, Bit32u *out, int base)
+{
+  Bit32u n = max + 1;
+  char buffer[1024];
+  char *clean;
+  int illegal;
+  assert (base==10 || base==16);
+  while (1) {
+    printf (prompt, the_default);
+    if (!fgets (buffer, sizeof(buffer), stdin))
+      return -1;
+    clean = clean_string (buffer);
+    if (strlen(clean) < 1) {
+      // empty line, use the default
+      *out = the_default;
+      return 0;
+    }
+    const char *format = (base==10) ? "%d" : "%x";
+    illegal = (1 != sscanf (buffer, format, &n));
+    if (illegal || n<min || n>max) {
+      printf ("Your choice (%s) was not an integer between %u and %u.\n\n",
+         clean, min, max);
+    } else {
+      // choice is okay
+      *out = n;
+      return 0;
+    }
+  }
+}
+
+// identical to ask_uint, but uses signed comparisons
+int 
+ask_int (char *prompt, Bit32s min, Bit32s max, Bit32s the_default, Bit32s *out)
+{
+  int n = max + 1;
+  char buffer[1024];
+  char *clean;
+  int illegal;
+  while (1) {
+    printf (prompt, the_default);
+    if (!fgets (buffer, sizeof(buffer), stdin))
+      return -1;
+    clean = clean_string (buffer);
+    if (strlen(clean) < 1) {
+      // empty line, use the default
+      *out = the_default;
+      return 0;
+    }
+    illegal = (1 != sscanf (buffer, "%d", &n));
+    if (illegal || n<min || n>max) {
+      printf ("Your choice (%s) was not an integer between %d and %d.\n\n",
+         clean, min, max);
+    } else {
+      // choice is okay
+      *out = n;
+      return 0;
+    }
+  }
+}
+
+int 
+ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out)
+{
+  char buffer[1024];
+  char *clean;
+  int i;
+  *out = -1;
+  while (1) {
+    printf (prompt, choice[the_default]);
+    if (!fgets (buffer, sizeof(buffer), stdin))
+      return -1;
+    clean = clean_string (buffer);
+    if (strlen(clean) < 1) {
+      // empty line, use the default
+      *out = the_default;
+      return 0;
+    }
+    for (i=0; i<n_choices; i++) {
+      if (!strcmp (choice[i], clean)) {
+       // matched, return the choice number
+       *out = i;
+       return 0;
+      }
+    }
+    if (clean[0] != '?')
+      printf ("Your choice (%s) did not match any of the choices:\n", clean);
+    for (i=0; i<n_choices; i++) {
+      if (i>0) printf (", ");
+      printf ("%s", choice[i]);
+    }
+    printf ("\n");
+  }
+}
+
+int 
+ask_yn (char *prompt, Bit32u the_default, Bit32u *out)
+{
+  char buffer[16];
+  char *clean;
+  *out = 1<<31;
+  while (1) {
+    // if there's a %s field, substitute in the default yes/no.
+    printf (prompt, the_default ? "yes" : "no");
+    if (!fgets (buffer, sizeof(buffer), stdin))
+      return -1;
+    clean = clean_string (buffer);
+    if (strlen(clean) < 1) {
+      // empty line, use the default
+      *out = the_default;
+      return 0;
+    }
+    switch (tolower(clean[0])) {
+      case 'y': *out=1; return 0;
+      case 'n': *out=0; return 0;
+    }
+    printf ("Please type either yes or no.\n");
+  }
+}
+
+// returns -1 on error (stream closed or  something)
+// returns 0 if default was taken
+// returns 1 if value changed
+int 
+ask_string (char *prompt, char *the_default, char *out)
+{
+  char buffer[1024];
+  char *clean;
+  assert (the_default != out);
+  out[0] = 0;
+  printf (prompt, the_default);
+  if (fgets (buffer, sizeof(buffer), stdin) == NULL)
+    return -1;
+  clean = clean_string (buffer);
+  if (strlen(clean) < 1) {
+    // empty line, use the default
+    strcpy (out, the_default);
+    return 0;
+  }
+  strcpy (out, clean);
+  return 1;
+}
+
+/******************************************************************/
+
+static char *startup_menu_prompt =
+"------------------------------\n"
+"Bochs Configuration: Main Menu\n"
+"------------------------------\n"
+"\n"
+"This is the Bochs Configuration Interface, where you can describe the\n"
+"machine that you want to simulate.  Bochs has already searched for a\n"
+"configuration file (typically called bochsrc.txt) and loaded it if it\n"
+"could be found.  When you are satisfied with the configuration, go\n"
+"ahead and start the simulation.\n"
+"\n"
+"You can also start bochs with the -q option to skip these menus.\n"
+"\n"
+"1. Restore factory default configuration\n"
+"2. Read options from...\n"
+"3. Edit options\n"
+"4. Save options to...\n"
+"5. Begin simulation\n"
+"6. Quit now\n"
+"\n"
+"Please choose one: [%d] ";
+
+static char *startup_options_prompt =
+"------------------\n"
+"Bochs Options Menu\n"
+"------------------\n"
+"0. Return to previous menu\n"
+"1. Log file: %s\n"
+"2. Log prefix: %s\n"
+"3. Debug log file: %s\n"
+"4. Log options for all devices\n"
+"5. Log options for individual devices\n"
+"6. Memory options\n"
+"7. Interface options\n"
+"8. Disk options\n"
+"9. Serial or Parallel port options\n"
+"10. Sound Blaster 16 options\n"
+"11. NE2000 network card options\n"
+"12. Keyboard options\n"
+"13. Other options\n"
+"\n"
+"Please choose one: [0] ";
+
+static char *runtime_menu_prompt =
+"---------------------\n"
+"Bochs Runtime Options\n"
+"---------------------\n"
+"1. Floppy disk 0: %s\n"
+"2. Floppy disk 1: %s\n"
+"3. 1st CDROM: %s\n"
+"4. 2nd CDROM: %s\n"
+"5. 3rd CDROM: %s\n"
+"6. 4th CDROM: %s\n"
+"7. (not implemented)\n"
+"8. Log options for all devices\n"
+"9. Log options for individual devices\n"
+"10. VGA Update Interval: %d\n"
+"11. Mouse: %s\n"
+"12. Keyboard paste delay: %d\n"
+"13. Userbutton shortcut: %s\n"
+"14. Instruction tracing: off (doesn't exist yet)\n"
+"15. Continue simulation\n"
+"16. Quit now\n"
+"\n"
+"Please choose one:  [15] ";
+
+#define NOT_IMPLEMENTED(choice) \
+  fprintf (stderr, "ERROR: choice %d not implemented\n", choice);
+
+#define BAD_OPTION(menu,choice) \
+  do {fprintf (stderr, "ERROR: menu %d has no choice %d\n", menu, choice); \
+      assert (0); } while (0)
+
+void build_runtime_options_prompt (char *format, char *buf, int size)
+{
+  bx_floppy_options floppyop;
+  bx_atadevice_options cdromop;
+/*  bx_param_num_c *ips = SIM->get_param_num (BXP_IPS); */
+  char buffer[6][128];
+  for (int i=0; i<2; i++) {
+    SIM->get_floppy_options (i, &floppyop);
+    if (floppyop.Odevtype->get () == BX_FLOPPY_NONE)
+      strcpy (buffer[i], "(not present)");
+    else {
+      sprintf (buffer[i], "%s, size=%s, %s", floppyop.Opath->getptr (),
+        SIM->get_floppy_type_name (floppyop.Otype->get ()),
+        (floppyop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected");
+      if (!floppyop.Opath->getptr ()[0]) strcpy (buffer[i], "none");
+    }
+  }
+
+  // 4 cdroms supported at run time
+  int device;
+  for (Bit8u cdrom=0; cdrom<4; cdrom++) {
+    if (!SIM->get_cdrom_options (cdrom, &cdromop, &device) || !cdromop.Opresent->get ())
+      sprintf (buffer[2+cdrom], "(not present)");
+    else
+      sprintf (buffer[2+cdrom], "(%s on ata%d) %s, %s",
+        device&1?"slave":"master", device/2, cdromop.Opath->getptr (),
+        (cdromop.Ostatus->get () == BX_INSERTED)? "inserted" : "ejected");
+    }
+
+  snprintf (buf, size, format, buffer[0], buffer[1], buffer[2], 
+      buffer[3], buffer[4], buffer[5],
+      /* ips->get (), */
+      SIM->get_param_num (BXP_VGA_UPDATE_INTERVAL)->get (), 
+      SIM->get_param_num (BXP_MOUSE_ENABLED)->get () ? "enabled" : "disabled",
+      SIM->get_param_num (BXP_KBD_PASTE_DELAY)->get (),
+      SIM->get_param_string (BXP_USER_SHORTCUT)->getptr ());
+}
+
+int do_menu (bx_id id) {
+  bx_list_c *menu = (bx_list_c *)SIM->get_param (id);
+  while (1) {
+    menu->get_choice()->set (0);
+    int status = menu->text_ask (stdin, stderr);
+    if (status < 0) return status;
+    bx_param_num_c *choice = menu->get_choice();
+    if (choice->get () < 1)
+      return choice->get ();
+    else {
+      int index = choice->get () - 1;  // choosing 1 means list[0]
+      bx_param_c *chosen = menu->get (index);
+      assert (chosen != NULL);
+      chosen->text_ask (stdin, stderr);
+    }
+  }
+}
+
+void askparam (bx_id id)
+{
+  bx_param_c *param = SIM->get_param (id);
+  param->text_ask (stdin, stderr);
+}
+
+int bx_config_interface (int menu)
+{
+ Bit32u choice;
+ while (1) {
+  switch (menu)
+  {
+   case BX_CI_INIT:
+     bx_config_interface_init ();
+     return 0;
+   case BX_CI_START_SIMULATION: {
+     SIM->begin_simulation (bx_startup_flags.argc, bx_startup_flags.argv);
+     // we don't expect it to return, but if it does, quit
+     SIM->quit_sim(1);
+     break;
+     }
+   case BX_CI_START_MENU:
+     {
+       Bit32u default_choice;
+       switch (SIM->get_param_enum(BXP_BOCHS_START)->get ()) {
+         case BX_LOAD_START: 
+           default_choice = 2; break;
+         case BX_EDIT_START: 
+           default_choice = 3; break;
+         default: 
+           default_choice = 5; break;
+       }
+
+       if (ask_uint (startup_menu_prompt, 1, 6, default_choice, &choice, 10) < 0) return -1;
+       switch (choice) {
+        case 1:
+          fprintf (stderr, "I reset all options back to their factory defaults.\n\n");
+          SIM->reset_all_param ();
+          SIM->get_param_enum(BXP_BOCHS_START)->set(BX_EDIT_START);
+          break;
+        case 2: 
+          // Before reading a new configuration, reset every option to its
+          // original state.
+          SIM->reset_all_param ();
+          if (bx_read_rc (NULL) >= 0)
+            SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START);
+          break;
+        case 3: 
+           bx_config_interface (BX_CI_START_OPTS); 
+          SIM->get_param_enum(BXP_BOCHS_START)->set(BX_RUN_START);
+           break;
+        case 4: bx_write_rc (NULL); break;
+        case 5: bx_config_interface (BX_CI_START_SIMULATION); break;
+        case 6: SIM->quit_sim (1); return -1;
+        default: BAD_OPTION(menu, choice);
+       }
+     }
+     break;
+   case BX_CI_START_OPTS:
+     {
+       char prompt[CI_PATH_LENGTH];
+       char oldpath[CI_PATH_LENGTH];
+       char olddebuggerpath[CI_PATH_LENGTH];
+       char oldprefix[CI_PATH_LENGTH];
+       int  retval;
+
+       retval = SIM->get_log_file (oldpath, CI_PATH_LENGTH);
+       assert (retval >= 0);
+       double_percent(oldpath,CI_PATH_LENGTH);
+       retval = SIM->get_log_prefix (oldprefix, CI_PATH_LENGTH);
+       assert (retval >= 0);
+       double_percent(oldprefix,CI_PATH_LENGTH);
+       retval = SIM->get_debugger_log_file (olddebuggerpath, CI_PATH_LENGTH);
+       assert (retval >= 0);
+       double_percent(olddebuggerpath,CI_PATH_LENGTH);
+
+       sprintf (prompt, startup_options_prompt, oldpath, oldprefix, olddebuggerpath);
+       if (ask_uint (prompt, 0, 13, 0, &choice, 10) < 0) return -1;
+       switch (choice) {
+        case 0: return 0;
+        case 1: askparam (BXP_LOG_FILENAME); break;
+        case 2: askparam (BXP_LOG_PREFIX); break;
+        case 3: askparam (BXP_DEBUGGER_LOG_FILENAME); break;
+        case 4: bx_log_options (0); break;
+        case 5: bx_log_options (1); break;
+        case 6: do_menu (BXP_MENU_MEMORY); break;
+        case 7: do_menu (BXP_MENU_INTERFACE); break;
+        case 8: do_menu (BXP_MENU_DISK); break;
+        case 9: do_menu (BXP_MENU_SERIAL_PARALLEL); break;
+        case 10: do_menu (BXP_SB16); break;
+        case 11: do_menu (BXP_NE2K); break;
+        case 12: do_menu (BXP_MENU_KEYBOARD); break;
+        case 13: do_menu (BXP_MENU_MISC); break;
+        default: BAD_OPTION(menu, choice);
+       }
+     }
+     break;
+   case BX_CI_RUNTIME:
+     char prompt[1024];
+     bx_floppy_options floppyop;
+     bx_atadevice_options cdromop;
+     build_runtime_options_prompt (runtime_menu_prompt, prompt, 1024);
+     if (ask_uint (prompt, 1, 16, 15, &choice, 10) < 0) return -1;
+     switch (choice) {
+       case 1: 
+         SIM->get_floppy_options (0, &floppyop);
+        if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYA);
+        break;
+       case 2:
+         SIM->get_floppy_options (1, &floppyop);
+        if (floppyop.Odevtype->get () != BX_FLOPPY_NONE) do_menu (BXP_FLOPPYB);
+        break;
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+        int device;
+         if (SIM->get_cdrom_options (choice - 3, &cdromop, &device) && cdromop.Opresent->get ()) {
+          // disable type selection
+          SIM->get_param((bx_id)(BXP_ATA0_MASTER_TYPE + device))->set_enabled(0);
+          SIM->get_param((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled(0);
+          SIM->get_param((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled(0);
+           do_menu ((bx_id)(BXP_ATA0_MASTER + device));
+           }
+        break;
+       case 7: // not implemented yet because I would have to mess with
+              // resetting timers and pits and everything on the fly.
+               // askparam (BXP_IPS);
+              break;
+       case 8: bx_log_options (0); break;
+       case 9: bx_log_options (1); break;
+       case 10: askparam (BXP_VGA_UPDATE_INTERVAL); break;
+       case 11: askparam (BXP_MOUSE_ENABLED); break;
+       case 12: askparam (BXP_KBD_PASTE_DELAY); break;
+       case 13: askparam (BXP_USER_SHORTCUT); break;
+       case 14: NOT_IMPLEMENTED (choice); break;
+       case 15: fprintf (stderr, "Continuing simulation\n"); return 0;
+       case 16:
+        fprintf (stderr, "You chose quit on the configuration interface.\n");
+        SIM->quit_sim (1);
+        return -1;
+       default: fprintf (stderr, "Menu choice %d not implemented.\n", choice);
+     }
+     break;
+   default:
+     fprintf (stderr, "Unknown config interface menu type.\n");
+     assert (menu >=0 && menu < BX_CI_N_MENUS);
+  }
+ }
+}
+
+static void bx_print_log_action_table ()
+{
+  // just try to print all the prefixes first.
+  fprintf (stderr, "Current log settings:\n");
+  fprintf (stderr, "                 Debug      Info       Error       Panic       Pass\n");
+  fprintf (stderr, "ID    Device     Action     Action     Action      Action      Action\n");
+  fprintf (stderr, "----  ---------  ---------  ---------  ----------  ----------  ----------\n");
+  int i, j, imax=SIM->get_n_log_modules ();
+  for (i=0; i<imax; i++) {
+    if (strcmp(SIM->get_prefix(i), "[     ]")) {
+      fprintf (stderr, "%3d.  %s ", i, SIM->get_prefix (i));
+      for (j=0; j<SIM->get_max_log_level (); j++) {
+        fprintf (stderr, "%10s ", SIM->get_action_name (SIM->get_log_action (i, j)));
+      }
+      fprintf (stderr, "\n");
+    }
+  }
+}
+
+static char *log_options_prompt1 = "Enter the ID of the device to edit, or -1 to return: [-1] ";
+static char *log_level_choices[] = { "ignore", "report", "ask", "fatal", "no change" };
+static int log_level_n_choices_normal = 4;
+
+void bx_log_options (int individual)
+{
+  if (individual) {
+    int done = 0;
+    while (!done) {
+      bx_print_log_action_table ();
+      Bit32s id, level, action;
+      Bit32s maxid = SIM->get_n_log_modules ();
+      if (ask_int (log_options_prompt1, -1, maxid-1, -1, &id) < 0)
+       return;
+      if (id < 0) return;
+      fprintf (stderr, "Editing log options for the device %s\n", SIM->get_prefix (id));
+      for (level=0; level<SIM->get_max_log_level (); level++) {
+       char prompt[1024];
+       int default_action = SIM->get_log_action (id, level);
+       sprintf (prompt, "Enter action for %s event: [%s] ", SIM->get_log_level_name (level), SIM->get_action_name(default_action));
+       // don't show the no change choice (choices=3)
+       if (ask_menu (prompt, log_level_n_choices_normal, log_level_choices, default_action, &action)<0)
+         return;
+       SIM->set_log_action (id, level, action);
+      }
+    }
+  } else {
+    // provide an easy way to set log options for all devices at once
+    bx_print_log_action_table ();
+    for (int level=0; level<SIM->get_max_log_level (); level++) {
+      char prompt[1024];
+      int action, default_action = 3;  // default to no change
+      sprintf (prompt, "Enter action for %s event on all devices: [no change] ", SIM->get_log_level_name (level));
+       // do show the no change choice (choices=4)
+      if (ask_menu (prompt, log_level_n_choices_normal+1, log_level_choices, default_action, &action)<0)
+       return;
+      if (action < 3) {
+       SIM->set_default_log_action (level, action);
+       SIM->set_log_action (-1, level, action);
+      }
+    }
+  }
+}
+
+int bx_read_rc (char *rc)
+{
+  if (rc && SIM->read_rc (rc) >= 0) return 0;
+  char oldrc[CI_PATH_LENGTH];
+  if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0)
+    strcpy (oldrc, "none");
+  char newrc[CI_PATH_LENGTH];
+  while (1) {
+    if (ask_string ("\nWhat is the configuration file name?\nTo cancel, type 'none'. [%s] ", oldrc, newrc) < 0) return -1;
+    if (!strcmp (newrc, "none")) return -1;
+    if (SIM->read_rc (newrc) >= 0) return 0;
+    fprintf (stderr, "The file '%s' could not be found.\n", newrc);
+  }
+}
+
+int bx_write_rc (char *rc)
+{
+  char oldrc[CI_PATH_LENGTH], newrc[CI_PATH_LENGTH];
+  if (rc == NULL) {
+    if (SIM->get_default_rc (oldrc, CI_PATH_LENGTH) < 0)
+      strcpy (oldrc, "none");
+  } else {
+    strncpy (oldrc, rc, CI_PATH_LENGTH);
+  }
+  while (1) {
+    if (ask_string ("Save configuration to what file?  To cancel, type 'none'.\n[%s] ", oldrc, newrc) < 0) return -1;
+    if (!strcmp (newrc, "none")) return 0;
+    // try with overwrite off first
+    int status = SIM->write_rc (newrc, 0);
+    if (status >= 0) {
+      fprintf (stderr, "Wrote configuration to '%s'.\n", newrc);
+      return 0;
+    } else if (status == -2) {
+      // return code -2 indicates the file already exists, and overwrite
+      // confirmation is required.
+      Bit32u overwrite = 0;
+      char prompt[256];
+      sprintf (prompt, "Configuration file '%s' already exists.  Overwrite it? [no] ", newrc);
+      if (ask_yn (prompt, 0, &overwrite) < 0) return -1;
+      if (!overwrite) continue;  // if "no", start loop over, asking for a different file
+      // they confirmed, so try again with overwrite bit set
+      if (SIM->write_rc (newrc, 1) >= 0) {
+       fprintf (stderr, "Overwriting existing configuration '%s'.\n", newrc);
+       return 0;
+      } else {
+       fprintf (stderr, "Write failed to '%s'.\n", newrc);
+      }
+    }
+  }
+}
+
+char *log_action_ask_choices[] = { "cont", "alwayscont", "die", "abort", "debug" };
+int log_action_n_choices = 4 + (BX_DEBUGGER?1:0);
+
+BxEvent *
+config_interface_notify_callback (void *unused, BxEvent *event)
+{
+#ifdef WIN32
+  int opts;
+  bx_param_c *param;
+  bx_param_string_c *sparam;
+#endif
+  event->retcode = -1;
+  switch (event->type)
+  {
+    case BX_SYNC_EVT_TICK:
+      event->retcode = 0;
+      return event;
+    case BX_SYNC_EVT_ASK_PARAM:
+#ifdef WIN32
+      param = event->u.param.param;
+      if (param->get_type() == BXT_PARAM_STRING) {
+        sparam = (bx_param_string_c *)param;
+        opts = sparam->get_options()->get();
+        if (opts & sparam->IS_FILENAME) {
+          if (param->get_id() == BXP_NULL) {
+            event->retcode = AskFilename(GetBochsWindow(), (bx_param_filename_c *)sparam);
+          } else {
+            event->retcode = FloppyDialog((bx_param_filename_c *)sparam);
+          }
+          return event;
+        } else {
+          event->retcode = AskString(sparam);
+          return event;
+        }
+      }
+#endif
+      event->u.param.param->text_ask (stdin, stderr);
+      return event;
+    case BX_SYNC_EVT_LOG_ASK:
+    {
+#ifdef WIN32
+      LogAskDialog(event);
+#else
+      int level = event->u.logmsg.level;
+      fprintf (stderr, "\a========================================================================\n");
+      fprintf (stderr, "Event type: %s\n", SIM->get_log_level_name (level));
+      fprintf (stderr, "Device: %s\n", event->u.logmsg.prefix);
+      fprintf (stderr, "Message: %s\n\n", event->u.logmsg.msg);
+      fprintf (stderr, "A %s has occurred.  Do you want to:\n", SIM->get_log_level_name (level));
+      fprintf (stderr, "  cont       - continue execution\n");
+      fprintf (stderr, "  alwayscont - continue execution, and don't ask again.\n");
+      fprintf (stderr, "               This affects only %s events from device %s\n", SIM->get_log_level_name (level), event->u.logmsg.prefix);
+      fprintf (stderr, "  die        - stop execution now\n");
+      fprintf (stderr, "  abort      - dump core %s\n", 
+         BX_HAVE_ABORT ? "" : "(Disabled)");
+#if BX_DEBUGGER
+      fprintf (stderr, "  debug      - continue and return to bochs debugger\n");
+#endif
+      int choice;
+ask:
+      if (ask_menu ("Choose one of the actions above: [%s] ", 
+           log_action_n_choices, log_action_ask_choices, 2, &choice) < 0) 
+       event->retcode = -1;
+      // return 0 for continue, 1 for alwayscontinue, 2 for die, 3 for debug.
+      if (!BX_HAVE_ABORT && choice==BX_LOG_ASK_CHOICE_DUMP_CORE) goto ask;
+      fflush(stdout);
+      fflush(stderr);
+      event->retcode = choice;
+#endif
+    }
+    return event;
+  case BX_ASYNC_EVT_REFRESH:
+  case BX_ASYNC_EVT_DBG_MSG:
+    // The text mode interface does not use these events, so just ignore
+    // them.
+    return event;
+  default:
+    fprintf (stderr, "Control panel: notify callback called with event type %04x\n", event->type);
+    return event;
+  }
+  assert (0); // switch statement should return
+}
+
+void bx_config_interface_init () {
+  //fprintf (stderr, "bx_config_interface_init()\n");
+  SIM->set_notify_callback (config_interface_notify_callback, NULL);
+}
+
+/////////////////////////////////////////////////////////////////////
+// implement the text_* methods for bx_param types.
+
+void
+bx_param_num_c::text_print (FILE *fp)
+{
+  //fprintf (fp, "number parameter, id=%u, name=%s\n", get_id (), get_name ());
+  //fprintf (fp, "value=%u\n", get ());
+  if (get_format ()) {
+    fprintf (fp, get_format (), get ());
+  } else {
+    char *format = "%s: %d"; 
+    assert (base==10 || base==16);
+    if (base==16) format = "%s: 0x%x";
+    fprintf (fp, format, get_name (), get ());
+  }
+}
+
+void
+bx_param_bool_c::text_print (FILE *fp)
+{
+  if (get_format ()) {
+    fprintf (fp, get_format (), get () ? "yes" : "no");
+  } else {
+    char *format = "%s: %s"; 
+    fprintf (fp, format, get_name (), get () ? "yes" : "no");
+  }
+}
+
+void
+bx_param_enum_c::text_print (FILE *fp)
+{
+  int n = get ();
+  assert (n >= min && n <= max);
+  char *choice = choices[n - min];
+  if (get_format ()) {
+    fprintf (fp, get_format (), choice);
+  } else {
+    char *format = "%s: %s"; 
+    fprintf (fp, format, get_name (), choice);
+  }
+}
+
+void
+bx_param_string_c::text_print (FILE *fp)
+{
+  char *value = getptr ();
+  int opts = options->get ();
+  if (opts & RAW_BYTES) {
+    char buffer[1024];
+    buffer[0] = 0;
+    char sep_string[2];
+    sep_string[0] = separator;
+    sep_string[1] = 0;
+    for (int i=0; i<maxsize; i++) {
+      char eachbyte[16];
+      sprintf (eachbyte, "%s%02x", (i>0)?sep_string : "", (unsigned int)0xff&val[i]);
+      strncat (buffer, eachbyte, sizeof(buffer));
+    }
+    if (strlen (buffer) > sizeof(buffer)-4) {
+      assert (0); // raw byte print buffer is probably overflowing. increase the max or make it dynamic
+    }
+    value = buffer;
+  }
+  if (get_format ()) {
+    fprintf (fp, get_format (), value);
+  } else {
+    fprintf (fp, "%s: %s", get_name (), value);
+  }
+}
+
+void
+bx_list_c::text_print (FILE *fp)
+{
+  //fprintf (fp, "This is a list.\n");
+  //fprintf (fp, "title=%s\n", title->getptr ());
+  fprintf (fp, "%s: ", get_name ());
+  /*
+  fprintf (fp, "options=%s%s%s\n", 
+      (options->get () == 0) ? "none" : "",
+      (options->get () & SHOW_PARENT) ? "SHOW_PARENT " : "",
+      (options->get () & SERIES_ASK) ? "SERIES_ASK " : "");
+      */
+  for (int i=0; i<size; i++) {
+    //fprintf (fp, "param[%d] = %p\n", i, list[i]);
+    assert (list[i] != NULL);
+    if (list[i]->get_enabled ()) {
+      if ((i>0) && (options->get () & SERIES_ASK))
+        fprintf (fp, ", ");
+      list[i]->text_print (fp);
+      if (!(options->get () & SERIES_ASK))
+        fprintf (fp, "\n");
+    }
+  }
+}
+
+int 
+bx_param_num_c::text_ask (FILE *fpin, FILE *fpout)
+{
+  fprintf (fpout, "\n");
+  int status;
+  char *prompt = get_ask_format ();
+  if (prompt == NULL) {
+    // default prompt, if they didn't set an ask format string
+    text_print (fpout);
+    fprintf (fpout, "\n");
+    prompt = "Enter new value: [%d] ";
+    if (base==16)
+      prompt = "Enter new value in hex: [%x] ";
+  }
+  Bit32u n = get ();
+  status = ask_uint (prompt, min, max, n, &n, base);
+  if (status < 0) return status;
+  set (n);
+  return 0;
+}
+
+int 
+bx_param_bool_c::text_ask (FILE *fpin, FILE *fpout)
+{
+  fprintf (fpout, "\n");
+  int status;
+  char *prompt = get_ask_format ();
+  char buffer[512];
+  if (prompt == NULL) {
+    // default prompt, if they didn't set an ask format string
+    sprintf (buffer, "%s? [%%s] ", get_name ());
+    prompt = buffer;
+  }
+  Bit32u n = get ();
+  status = ask_yn (prompt, n, &n);
+  if (status < 0) return status;
+  set (n);
+  return 0;
+}
+
+int 
+bx_param_enum_c::text_ask (FILE *fpin, FILE *fpout)
+{
+  fprintf (fpout, "\n");
+  char *prompt = get_ask_format ();
+  if (prompt == NULL) {
+    // default prompt, if they didn't set an ask format string
+    fprintf (fpout, "%s = ", get_name ());
+    text_print (fpout);
+    fprintf (fpout, "\n");
+    prompt = "Enter new value: [%s] ";
+  }
+  Bit32s n = (Bit32s)(get () - min);
+  int status = ask_menu (prompt, (max-min+1), choices, n, &n);
+  if (status < 0) return status;
+  n += (Bit32s)min;
+  set (n);
+  return 0;
+}
+
+int parse_raw_bytes (char *dest, char *src, int destsize, char separator)
+{
+  //printf ("parsing src='%s'\n", src);
+  int i;
+  unsigned int n;
+  for (i=0; i<destsize; i++) 
+    dest[i] = 0;
+  for (i=0; i<destsize; i++) {
+    while (*src == separator)
+      src++;
+    if (*src == 0) break;
+    // try to read a byte of hex
+    if (sscanf (src, "%02x", &n) == 1) {
+      //printf ("found a byte %02x\n", n);
+      dest[i] = n;
+      src+=2;
+    } else {
+      return -1;
+    }
+  }
+  return 0;
+}
+
+int 
+bx_param_string_c::text_ask (FILE *fpin, FILE *fpout)
+{
+  fprintf (fpout, "\n");
+  int status;
+  char *prompt = get_ask_format ();
+  if (prompt == NULL) {
+    // default prompt, if they didn't set an ask format string
+    text_print (fpout);
+    fprintf (fpout, "\n");
+    prompt = "Enter a new value, or press return for no change.\n";
+  }
+  while (1) {
+    char buffer[1024];
+    status = ask_string (prompt, getptr(), buffer);
+    if (status < 0) return status;
+    int opts = options->get ();
+    char buffer2[1024];
+    strcpy (buffer2, buffer);
+    if (status == 1 && opts & RAW_BYTES) {
+      // copy raw hex into buffer
+      status = parse_raw_bytes (buffer, buffer2, maxsize, separator);
+      if (status < 0) {
+       fprintf (fpout, "Illegal raw byte format.  I expected something like 3A%c03%c12%c...\n", separator, separator, separator);
+       continue;
+      }
+    }
+    if (!equals (buffer)) 
+      set (buffer);
+    return 0;
+  }
+}
+
+int
+bx_list_c::text_ask (FILE *fpin, FILE *fpout)
+{
+  char *my_title = title->getptr ();
+  fprintf (fpout, "\n");
+  int i, imax = strlen (my_title);
+  for (i=0; i<imax; i++) fprintf (fpout, "-");
+  fprintf (fpout, "\n%s\n", my_title);
+  for (i=0; i<imax; i++) fprintf (fpout, "-");
+  fprintf (fpout, "\n"); //fprintf (fp, "options=%s\n", options->get ());
+  if (options->get () & SERIES_ASK) {
+    for (int i=0; i<size; i++) {
+      if (list[i]->get_enabled ())
+        list[i]->text_ask (fpin, fpout);
+    }
+  } else {
+    if (options->get () & SHOW_PARENT)
+      fprintf (fpout, "0. Return to previous menu\n");
+    for (int i=0; i<size; i++) {
+      assert (list[i] != NULL);
+      fprintf (fpout, "%d. ", i+1);
+      if (list[i]->get_enabled ()) {
+        list[i]->text_print (fpout);
+       fprintf (fpout, "\n");
+      } else
+       fprintf (fpout, "(disabled)\n");
+    }
+    fprintf (fpout, "\n");
+    Bit32u n = choice->get ();
+    int min = (options->get () & SHOW_PARENT) ? 0 : 1;
+    int max = size;
+    int status = ask_uint ("Please choose one: [%d] ", min, max, n, &n, 10);
+    if (status < 0) return status;
+    choice->set (n);
+  }
+  return 0;
+}
+
+static int ci_callback (void *userdata, ci_command_t command)
+{
+  switch (command)
+  {
+    case CI_START:
+      //fprintf (stderr, "textconfig.cc: start\n");
+      bx_config_interface_init ();
+      if (SIM->get_param_enum(BXP_BOCHS_START)->get () == BX_QUICK_START)
+       bx_config_interface (BX_CI_START_SIMULATION);
+      else {
+        if (!SIM->test_for_text_console ())
+         return CI_ERR_NO_TEXT_CONSOLE;
+        bx_config_interface (BX_CI_START_MENU);
+      }
+      break;
+    case CI_RUNTIME_CONFIG:
+      bx_config_interface (BX_CI_RUNTIME);
+      break;
+    case CI_SHUTDOWN:
+      //fprintf (stderr, "textconfig.cc: shutdown\n");
+      break;
+  }
+  return 0;
+}
+
+// if I can make things compile without this module linked in, then
+// this file can become a plugin too.
+int init_text_config_interface ()
+{
+  //fprintf (stderr, "plugin_init for textconfig.cc\n");
+  SIM->register_configuration_interface ("textconfig", ci_callback, NULL);
+  return 0;  // success
+}
diff --git a/tools/ioemu/gui/textconfig.h b/tools/ioemu/gui/textconfig.h
new file mode 100644 (file)
index 0000000..01687ca
--- /dev/null
@@ -0,0 +1,19 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: textconfig.h,v 1.1 2002/10/29 20:16:04 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+enum {
+  BX_CI_INIT,
+  BX_CI_START_MENU,
+  BX_CI_START_OPTS,
+  BX_CI_START_OPTS_MEM,
+  BX_CI_START_OPTS_INTERFACE,
+  BX_CI_START_OPTS_DISK,
+  BX_CI_START_OPTS_SOUND,
+  BX_CI_START_OPTS_MISC,
+  BX_CI_START_SIMULATION,
+  BX_CI_RUNTIME,
+  BX_CI_N_MENUS
+};
+
+int init_text_config_interface ();
diff --git a/tools/ioemu/gui/x.cc b/tools/ioemu/gui/x.cc
new file mode 100644 (file)
index 0000000..5d1cae9
--- /dev/null
@@ -0,0 +1,1848 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: x.cc,v 1.76 2003/08/11 19:27:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#define XK_PUBLISHING
+#define XK_TECHNICAL
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_WITH_X11
+
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#if BX_HAVE_XPM_H
+#include <X11/xpm.h>
+#endif
+}
+
+#if BX_HAVE_XPM_H
+#include "icon_bochs.xpm"
+#else
+#include "icon_bochs.h"
+#endif
+
+#include "font/vga.bitmap.h"
+
+class bx_x_gui_c : public bx_gui_c {
+public:
+  bx_x_gui_c (void);
+  DECLARE_GUI_VIRTUAL_METHODS()
+#if BX_USE_IDLE_HACK
+  virtual void sim_is_idle(void);
+#endif
+};
+
+// declare one instance of the gui object and call macro to insert the
+// plugin code
+static bx_x_gui_c *theGui = NULL;
+IMPLEMENT_GUI_PLUGIN_CODE(x)
+
+#define LOG_THIS theGui->
+
+#define MAX_MAPPED_STRING_LENGTH 10
+
+/* These are used as arguments to nearly every Xlib routine, so it saves
+ * routine arguments to declare them global.  If there were
+ * additional source files, they would be declared extern there. */
+Display *bx_x_display;
+int bx_x_screen_num;
+static Colormap default_cmap;
+static unsigned long white_pixel=0, black_pixel=0;
+
+static char *progname; /* name this program was invoked by */
+
+static unsigned int text_rows=25, text_cols=80;
+static Bit8u h_panning = 0, v_panning = 0;
+
+static Window win;
+static GC gc, gc_inv, gc_headerbar, gc_headerbar_inv;
+static unsigned font_width, font_height;
+static unsigned dimension_x=0, dimension_y=0;
+static unsigned vga_bpp=8;
+
+static XImage *ximage = NULL;
+static unsigned imDepth, imWide, imBPP;
+
+// current cursor coordinates
+static int prev_x=-1, prev_y=-1;
+static int current_x=-1, current_y=-1;
+static unsigned mouse_button_state = 0;
+
+static unsigned prev_cursor_x=0;
+static unsigned prev_cursor_y=0;
+
+static int warp_home_x = 200;
+static int warp_home_y = 200;
+static int mouse_enable_x = 0;
+static int mouse_enable_y = 0;
+static int warp_dx = 0;
+static int warp_dy = 0;
+
+static void warp_cursor(int dx, int dy);
+static void disable_cursor();
+static void enable_cursor();
+
+static Bit32u convertStringToXKeysym (const char *string);
+
+static bx_bool x_init_done = false;
+
+static Pixmap vgafont[256];
+
+struct {
+  Pixmap bmap;
+  unsigned xdim;
+  unsigned ydim;
+  } bx_bitmaps[BX_MAX_PIXMAPS];
+unsigned bx_bitmap_entries = 0;
+
+static struct {
+  Pixmap   bitmap;
+  unsigned xdim;
+  unsigned ydim;
+  unsigned xorigin;
+  unsigned yorigin;
+  unsigned alignment;
+  void (*f)(void);
+  } bx_headerbar_entry[BX_MAX_HEADERBAR_ENTRIES];
+static unsigned bx_headerbar_y = 0;
+static unsigned bx_headerbar_entries = 0;
+static unsigned bx_bitmap_left_xorigin = 0;  // pixels from left
+static unsigned bx_bitmap_right_xorigin = 0; // pixels from right
+
+static void headerbar_click(int x, int y);
+static void send_keyboard_mouse_status(void);
+
+
+
+
+Bit32u ascii_to_key_event[0x5f] = {
+  //  !"#$%&'
+  BX_KEY_SPACE,
+  BX_KEY_1,
+  BX_KEY_SINGLE_QUOTE,
+  BX_KEY_3,
+  BX_KEY_4,
+  BX_KEY_5,
+  BX_KEY_7,
+  BX_KEY_SINGLE_QUOTE,
+
+  // ()*+,-./
+  BX_KEY_9,
+  BX_KEY_0,
+  BX_KEY_8,
+  BX_KEY_EQUALS,
+  BX_KEY_COMMA,
+  BX_KEY_MINUS,
+  BX_KEY_PERIOD,
+  BX_KEY_SLASH,
+
+  // 01234567
+  BX_KEY_0,
+  BX_KEY_1,
+  BX_KEY_2,
+  BX_KEY_3,
+  BX_KEY_4,
+  BX_KEY_5,
+  BX_KEY_6,
+  BX_KEY_7,
+
+  // 89:;<=>?
+  BX_KEY_8,
+  BX_KEY_9,
+  BX_KEY_SEMICOLON,
+  BX_KEY_SEMICOLON,
+  BX_KEY_COMMA,
+  BX_KEY_EQUALS,
+  BX_KEY_PERIOD,
+  BX_KEY_SLASH,
+
+  // @ABCDEFG
+  BX_KEY_2,
+  BX_KEY_A,
+  BX_KEY_B,
+  BX_KEY_C,
+  BX_KEY_D,
+  BX_KEY_E,
+  BX_KEY_F,
+  BX_KEY_G,
+
+
+  // HIJKLMNO
+  BX_KEY_H,
+  BX_KEY_I,
+  BX_KEY_J,
+  BX_KEY_K,
+  BX_KEY_L,
+  BX_KEY_M,
+  BX_KEY_N,
+  BX_KEY_O,
+
+
+  // PQRSTUVW
+  BX_KEY_P,
+  BX_KEY_Q,
+  BX_KEY_R,
+  BX_KEY_S,
+  BX_KEY_T,
+  BX_KEY_U,
+  BX_KEY_V,
+  BX_KEY_W,
+
+  // XYZ[\]^_
+  BX_KEY_X,
+  BX_KEY_Y,
+  BX_KEY_Z,
+  BX_KEY_LEFT_BRACKET,
+  BX_KEY_BACKSLASH,
+  BX_KEY_RIGHT_BRACKET,
+  BX_KEY_6,
+  BX_KEY_MINUS,
+
+  // `abcdefg
+  BX_KEY_GRAVE,
+  BX_KEY_A,
+  BX_KEY_B,
+  BX_KEY_C,
+  BX_KEY_D,
+  BX_KEY_E,
+  BX_KEY_F,
+  BX_KEY_G,
+
+  // hijklmno
+  BX_KEY_H,
+  BX_KEY_I,
+  BX_KEY_J,
+  BX_KEY_K,
+  BX_KEY_L,
+  BX_KEY_M,
+  BX_KEY_N,
+  BX_KEY_O,
+
+  // pqrstuvw
+  BX_KEY_P,
+  BX_KEY_Q,
+  BX_KEY_R,
+  BX_KEY_S,
+  BX_KEY_T,
+  BX_KEY_U,
+  BX_KEY_V,
+  BX_KEY_W,
+
+  // xyz{|}~
+  BX_KEY_X,
+  BX_KEY_Y,
+  BX_KEY_Z,
+  BX_KEY_LEFT_BRACKET,
+  BX_KEY_BACKSLASH,
+  BX_KEY_RIGHT_BRACKET,
+  BX_KEY_GRAVE
+  };
+
+extern Bit8u graphics_snapshot[32 * 1024];
+
+
+static void create_internal_vga_font(void);
+static void xkeypress(KeySym keysym, int press_release);
+// extern "C" void select_visual(void);
+
+#define ROUNDUP(nbytes, pad) ((((nbytes) + ((pad)-1)) / (pad)) * ((pad)>>3))
+
+
+#define MAX_VGA_COLORS 256
+
+unsigned long col_vals[MAX_VGA_COLORS]; // 256 VGA colors
+unsigned curr_foreground, curr_background;
+
+static unsigned x_tilesize, y_tilesize;
+
+
+// Try to allocate NCOLORS at once in the colormap provided.  If it can
+// be done, return true.  If not, return false.  (In either case, free
+// up the color cells so that we don't add to the problem!)  This is used
+// to determine whether Bochs should use a private colormap even when the
+// user did not specify it.
+static bx_bool
+test_alloc_colors (Colormap cmap, Bit32u n_tries) {
+  XColor color;
+  unsigned long pixel[MAX_VGA_COLORS];
+  bx_bool pixel_valid[MAX_VGA_COLORS];
+  Bit32u n_allocated = 0;
+  Bit32u i;
+  color.flags = DoRed | DoGreen | DoBlue;
+  for (i=0; i<n_tries; i++) {
+    // choose wierd color values that are unlikely to already be in the 
+    // colormap.
+    color.red   = ((i+41)%MAX_VGA_COLORS) << 8;
+    color.green = ((i+42)%MAX_VGA_COLORS) << 8;
+    color.blue  = ((i+43)%MAX_VGA_COLORS) << 8;
+    pixel_valid[i] = false;
+    if (XAllocColor (bx_x_display, cmap, &color)) {
+      pixel[i] = color.pixel;
+      pixel_valid[i] = true;
+      n_allocated++;
+    }
+  }
+  BX_INFO (("test_alloc_colors: %d colors available out of %d colors tried", n_allocated, n_tries));
+  // now free them all
+  for (i=0; i<n_tries; i++) {
+    if (pixel_valid[i]) XFreeColors (bx_x_display, cmap, &pixel[i], 1, 0);
+  }
+  return (n_allocated == n_tries);
+}
+
+bx_x_gui_c::bx_x_gui_c () {
+}
+
+  void
+bx_x_gui_c::specific_init(int argc, char **argv, unsigned tilewidth, unsigned tileheight,
+                     unsigned headerbar_y)
+{
+  unsigned i;
+  int x, y;   /* window position */
+  unsigned int border_width = 4;  /* four pixels */
+#if BX_CPU_LEVEL < 2
+  char *window_name = "Bochs 8086 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 2
+  char *window_name = "Bochs 80286 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 3
+  char *window_name = "Bochs 80386 emulator, http://bochs.sourceforge.net/";
+#elif BX_CPU_LEVEL == 4
+  char *window_name = "Bochs 80486 emulator, http://bochs.sourceforge.net/";
+#else
+  char *window_name = "VTXen";
+#endif
+  char *icon_name = "Bochs";
+  Pixmap icon_pixmap;
+#if BX_HAVE_XPM_H
+  Pixmap icon_mask;
+#endif
+  XSizeHints size_hints;
+  char *display_name = NULL;
+  /* create GC for text and drawing */
+  unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
+  XGCValues values;
+  Visual  *default_visual;
+  int      default_depth;
+  XEvent report;
+  XSetWindowAttributes win_attr;
+  unsigned long plane_masks_return[1];
+  XColor color;
+
+  put("XGUI");
+
+  x_tilesize = tilewidth;
+  y_tilesize = tileheight;
+  bx_headerbar_y = headerbar_y;
+
+  progname = argv[0];
+
+  /* connect to X server */
+  if ( (bx_x_display=XOpenDisplay(display_name)) == NULL )
+  {
+    BX_PANIC(("%s: cannot connect to X server %s",
+        progname, XDisplayName(display_name)));
+  }
+
+  /* get screen size from display structure macro */
+  bx_x_screen_num = DefaultScreen(bx_x_display);
+
+  /* Note that in a real application, x and y would default to 0
+   * but would be settable from the command line or resource database.
+   */
+  x = y = 0;
+
+
+  // Temporary values so we can create the window
+  font_width = 8;
+  font_height = 16;
+
+  dimension_x = text_cols * font_width;
+  dimension_y = text_rows * font_height + headerbar_y;
+
+  /* create opaque window */
+  win = XCreateSimpleWindow(bx_x_display, RootWindow(bx_x_display,bx_x_screen_num),
+    x, y,
+    dimension_x,
+    dimension_y,
+    border_width,
+    BlackPixel(bx_x_display, bx_x_screen_num),
+    BlackPixel(bx_x_display, bx_x_screen_num));
+
+  // (attempt to) enable backing store
+  win_attr.save_under=1;
+  win_attr.backing_store=Always;
+  XChangeWindowAttributes(bx_x_display,win,CWSaveUnder|CWBackingStore,&win_attr);
+
+  default_depth  = DefaultDepth(bx_x_display, bx_x_screen_num);
+  default_visual = DefaultVisual(bx_x_display, bx_x_screen_num);
+
+  if (!bx_options.Oprivate_colormap->get ()) {
+    default_cmap = DefaultColormap(bx_x_display, bx_x_screen_num);
+    // try to use default colormap.  If not enough colors are available,
+    // then switch to private colormap despite the user setting.  There
+    // are too many cases when no colors are available and Bochs simply
+    // draws everything in black on black.
+    if (!test_alloc_colors (default_cmap, 16)) {
+      BX_ERROR (("I can't even allocate 16 colors!  Switching to a private colormap"));
+      bx_options.Oprivate_colormap->set (1);
+    }
+    col_vals[0]  = BlackPixel(bx_x_display, bx_x_screen_num);
+    col_vals[15] = WhitePixel(bx_x_display, bx_x_screen_num);
+    for (i = 1; i < MAX_VGA_COLORS; i++) {
+      if (i==15) continue;
+      col_vals[i] = col_vals[0];
+    }
+  }
+
+  if (bx_options.Oprivate_colormap->get ()) {
+    default_cmap = XCreateColormap(bx_x_display, DefaultRootWindow(bx_x_display),
+                                   default_visual, AllocNone);
+    if (XAllocColorCells(bx_x_display, default_cmap, False,
+                         plane_masks_return, 0, col_vals, MAX_VGA_COLORS) == 0) {
+      BX_PANIC(("XAllocColorCells returns error. Maybe your screen does not support a private colormap?"));
+      }
+
+    win_attr.colormap = default_cmap;
+    XChangeWindowAttributes(bx_x_display, win, CWColormap, &win_attr);
+
+    color.flags = DoRed | DoGreen | DoBlue;
+
+    for (i=0; i < MAX_VGA_COLORS; i++) {
+      color.pixel = i;
+      if (i==15) {
+        color.red   = 0xffff;
+        color.green = 0xffff;
+        color.blue  = 0xffff;
+        }
+      else {
+        color.red   = 0;
+        color.green = 0;
+        color.blue  = 0;
+        }
+      XStoreColor(bx_x_display, default_cmap, &color);
+      }
+    }
+
+  // convenience variables which hold the black & white color indeces
+  black_pixel = col_vals[0];
+  white_pixel = col_vals[15];
+
+  BX_INFO(("font %u wide x %u high, display depth = %d",
+               (unsigned) font_width, (unsigned) font_height, default_depth));
+
+  //select_visual();
+
+
+  /* Get available icon sizes from Window manager */
+
+#if BX_HAVE_XPM_H
+  /* Create pixmap from XPM for icon */
+  XCreatePixmapFromData(bx_x_display, win, icon_bochs_xpm, &icon_pixmap, &icon_mask, NULL);
+#else
+  /* Create pixmap of depth 1 (bitmap) for icon */
+  icon_pixmap = XCreateBitmapFromData(bx_x_display, win,
+    (char *) bochs_icon_bits, bochs_icon_width, bochs_icon_height);
+#endif
+
+  /* Set size hints for window manager.  The window manager may
+   * override these settings.  Note that in a real
+   * application if size or position were set by the user
+   * the flags would be UPosition and USize, and these would
+   * override the window manager's preferences for this window. */
+  /* x, y, width, and height hints are now taken from
+   * the actual settings of the window when mapped. Note
+   * that PPosition and PSize must be specified anyway. */
+
+  size_hints.flags = PPosition | PSize | PMinSize | PMaxSize;
+  size_hints.max_width = size_hints.min_width = dimension_x;
+  size_hints.max_height = size_hints.min_height = dimension_y;
+
+  {
+  XWMHints wm_hints;
+  XClassHint class_hints;
+
+  /* format of the window name and icon name
+   * arguments has changed in R4 */
+  XTextProperty windowName, iconName;
+
+  /* These calls store window_name and icon_name into
+   * XTextProperty structures and set their other
+   * fields properly. */
+  if (XStringListToTextProperty(&window_name, 1, &windowName) == 0) {
+    BX_PANIC(("%s: structure allocation for windowName failed.",
+        progname));
+  }
+
+  if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0) {
+    BX_PANIC(("%s: structure allocation for iconName failed.",
+        progname));
+  }
+
+  wm_hints.initial_state = NormalState;
+  wm_hints.input = True;
+  wm_hints.icon_pixmap = icon_pixmap;
+#if BX_HAVE_XPM_H
+  wm_hints.icon_mask = icon_mask;
+  wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
+#else
+  wm_hints.flags = StateHint | IconPixmapHint | InputHint;
+#endif
+  class_hints.res_name = progname;
+  class_hints.res_class = "Bochs";
+
+  XSetWMProperties(bx_x_display, win, &windowName, &iconName,
+      argv, argc, &size_hints, &wm_hints,
+      &class_hints);
+  }
+
+  /* Select event types wanted */
+  XSelectInput(bx_x_display, win, ExposureMask | KeyPressMask | KeyReleaseMask |
+      ButtonPressMask | ButtonReleaseMask | StructureNotifyMask | PointerMotionMask |
+      EnterWindowMask | LeaveWindowMask );
+
+
+  /* Create default Graphics Context */
+  gc               = XCreateGC(bx_x_display, win, valuemask, &values);
+  gc_inv           = XCreateGC(bx_x_display, win, valuemask, &values);
+  gc_headerbar     = XCreateGC(bx_x_display, win, valuemask, &values);
+  gc_headerbar_inv = XCreateGC(bx_x_display, win, valuemask, &values);
+
+  XSetState(bx_x_display, gc, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+  XSetState(bx_x_display, gc_inv, black_pixel, white_pixel, GXinvert,AllPlanes);
+
+  XSetState(bx_x_display, gc_headerbar, black_pixel, white_pixel, GXcopy,AllPlanes);
+
+  XSetState(bx_x_display, gc_headerbar_inv, white_pixel, black_pixel, GXcopy,AllPlanes);
+
+
+  /* Display window */
+  XMapWindow(bx_x_display, win);
+  XSync(bx_x_display, /* no discard */ 0);
+
+  BX_DEBUG(("waiting for MapNotify"));
+  while (1) {
+    XNextEvent(bx_x_display, &report);
+    if (report.type == MapNotify) break;
+    }
+  BX_DEBUG(("MapNotify found."));
+
+  // Create the VGA font
+  create_internal_vga_font();
+
+
+{
+  char *imagedata;
+
+  ximage = XCreateImage(bx_x_display, default_visual,
+             default_depth,          // depth of image (bitplanes)
+             ZPixmap,
+             0,                      // offset
+             NULL,                   // malloc() space after
+             x_tilesize, y_tilesize, // x & y size of image
+             32,                     // # bits of padding
+             0 );                    // bytes_per_line, let X11 calculate
+  if (!ximage)
+    BX_PANIC(("vga: couldn't XCreateImage()"));
+
+  imDepth = default_depth;
+  imWide  = ximage->bytes_per_line;
+  imBPP   = ximage->bits_per_pixel;
+
+  imagedata = (char *) malloc( (size_t) (ximage->bytes_per_line * y_tilesize) );
+  if (!imagedata) BX_PANIC(("imagedata: malloc returned error"));
+
+  ximage->data = imagedata;
+
+  if (imBPP < imDepth) {
+    BX_PANIC(("vga_x: bits_per_pixel < depth ?"));
+    }
+
+  x_init_done = true;
+
+}
+
+  curr_background = 0;
+  XSetBackground(bx_x_display, gc, col_vals[curr_background]);
+  curr_foreground = 1;
+  XSetForeground(bx_x_display, gc, col_vals[curr_foreground]);
+  //XGrabPointer( bx_x_display, win, True, 0, GrabModeAsync, GrabModeAsync,
+  //  win, None, CurrentTime );
+
+
+  XFlush(bx_x_display);
+
+  // loads keymap for x11
+  if(bx_options.keyboard.OuseMapping->get()) {
+    bx_keymap.loadKeymap(convertStringToXKeysym);
+    }
+}
+
+
+// This is called whenever the mouse_enabled parameter changes.  It
+// can change because of a gui event such as clicking on the mouse-enable
+// bitmap or pressing the middle button, or from the configuration interface.
+// In all those cases, setting the parameter value will get you here.
+  void
+bx_x_gui_c::mouse_enabled_changed_specific (bx_bool val)
+{
+  BX_DEBUG (("mouse_enabled=%d, x11 specific code", val?1:0));
+  if (val) {
+    BX_INFO(("[x] Mouse on"));
+    mouse_enable_x = current_x;
+    mouse_enable_y = current_y;
+    disable_cursor();
+    // Move the cursor to a 'safe' place
+    warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+  } else {
+    BX_INFO(("[x] Mouse off"));
+    enable_cursor();
+    warp_cursor(mouse_enable_x-current_x, mouse_enable_y-current_y);
+  }
+}
+
+  void
+create_internal_vga_font(void)
+{
+  // Default values
+  font_width=8;
+  font_height=16;
+
+  for(int i=0; i<256; i++) {
+    vgafont[i]=XCreateBitmapFromData(bx_x_display, win, (const char*)bx_vgafont[i].data,
+                                     font_width, font_height);
+    if(vgafont[i] == None)
+      BX_PANIC(("Can't create vga font [%d]", i));
+  }
+}
+
+  void
+bx_x_gui_c::handle_events(void)
+{
+  XEvent report;
+  XKeyEvent *key_event;
+  KeySym keysym;
+  XComposeStatus compose;
+  char buffer[MAX_MAPPED_STRING_LENGTH];
+  int bufsize = MAX_MAPPED_STRING_LENGTH;
+  int charcount;
+  bx_bool mouse_update;
+  int y, height;
+
+
+  XPointerMovedEvent *pointer_event;
+  XEnterWindowEvent *enter_event;
+  XLeaveWindowEvent *leave_event;
+  XButtonEvent *button_event;
+  XExposeEvent *expose_event;
+
+
+  //current_x = -1;
+  //current_y = -1;
+  mouse_update = 0;
+
+  while (XPending(bx_x_display) > 0)  {
+    XNextEvent(bx_x_display, &report);
+    switch  (report.type) {
+
+    case Expose:
+      expose_event = &report.xexpose;
+      /* Adjust y, and reduce height if it overlaps headerbar. */
+      y = expose_event->y - BX_HEADER_BAR_Y;
+      height = expose_event->height;
+      if (y < 0) {
+       height += y;
+       y = 0;
+      }
+
+      DEV_vga_redraw_area(
+        (unsigned) expose_event->x,
+        y,
+        (unsigned) expose_event->width,
+        height);
+
+      /* Always draw headerbar, even if not touched by expose event.
+       * As a small optimization, only do it on last contigous expose.
+       */
+      if (expose_event->count == 0) {
+      show_headerbar();
+      }
+      break;
+
+    case ConfigureNotify:
+      BX_DEBUG(("ConfigureNotify Xevent"));
+      /* FIXME: It's not clear why we have to show the headerbar here.
+       * This should be forced by the following expose events.
+       */
+      show_headerbar();
+      break;
+
+    case ButtonPress:
+      button_event = (XButtonEvent *) &report;
+               BX_DEBUG(("xxx: buttonpress"));
+      if (button_event->y < BX_HEADER_BAR_Y) {
+               BX_DEBUG(("xxx:   in headerbar"));
+        if (mouse_update) {
+                 BX_DEBUG(("xxx:   mouse_update=1"));
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          }
+        prev_x = current_x = -1;
+        prev_y = current_y = -1;
+        headerbar_click(button_event->x, button_event->y);
+        break;
+        }
+      current_x = button_event->x;
+      current_y = button_event->y;
+      mouse_update = 1;
+         BX_DEBUG(("xxx:   x,y=(%d,%d)", current_x, current_y));
+      switch (button_event->button) {
+        case Button1:
+                 BX_DEBUG(("xxx:   button1"));
+          mouse_button_state |= 0x01;
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          break;
+        case Button2:
+             BX_DEBUG(("XXX:   button2"));
+
+             // (mch) Hack for easier mouse handling (toggle mouse enable)
+             toggle_mouse_enable();
+
+          //mouse_button_state |= ;
+          //send_keyboard_mouse_status();
+          //mouse_update = 0;
+          break;
+        case Button3:
+                 BX_DEBUG(("xxx:   button3"));
+          mouse_button_state |= 0x02;
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          break;
+        }
+      break;
+
+    case ButtonRelease:
+      button_event = (XButtonEvent *) &report;
+//BX_INFO(("xxx: buttonrelease"));
+      if (button_event->y < BX_HEADER_BAR_Y) {
+//BX_INFO(("xxx:   in headerbar"));
+        if (mouse_update) {
+//BX_INFO(("xxx:   mouse_update=1"));
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          }
+        prev_x = current_x = -1;
+        prev_y = current_y = -1;
+        // ignore, in headerbar area
+        break;
+        }
+      current_x = button_event->x;
+      current_y = button_event->y;
+      mouse_update = 1;
+//BX_INFO(("xxx:   x,y=(%d,%d)", current_x, current_y));
+      switch (button_event->button) {
+        case Button1:
+//BX_INFO(("xxx:   button1"));
+          mouse_button_state &= ~0x01;
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          break;
+        case Button2:
+//BX_INFO(("xxx:   button2"));
+          //mouse_button_state &= ~;
+          //send_keyboard_mouse_status();
+          //mouse_update = 0;
+          break;
+        case Button3:
+//BX_INFO(("xxx:   button3"));
+          mouse_button_state &= ~0x02;
+          send_keyboard_mouse_status();
+          mouse_update = 0;
+          break;
+        }
+      break;
+
+    case KeyPress:
+      key_event = (XKeyEvent *) &report;
+      charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+      xkeypress(keysym, 0);
+      break;
+
+    case KeyRelease:
+      key_event = (XKeyEvent *) &report;
+      charcount = XLookupString(key_event, buffer, bufsize, &keysym, &compose);
+      xkeypress(keysym, 1);
+      break;
+
+    case MotionNotify:
+      pointer_event = (XPointerMovedEvent *) &report;
+      current_x = pointer_event->x;
+      current_y = pointer_event->y;
+      mouse_update = 1;
+//BX_INFO(("xxx: motionNotify x,y=(%d,%d)", current_x, current_y));
+      break;
+
+    case EnterNotify:
+      enter_event = (XEnterWindowEvent *) &report;
+      prev_x = current_x = enter_event->x;
+      prev_y = current_y = enter_event->y;
+//BX_INFO(("xxx: enterNotify x,y=(%d,%d)", current_x, current_y));
+      break;
+
+    case LeaveNotify:
+      leave_event = (XLeaveWindowEvent *) &report;
+      prev_x = current_x = -1;
+      prev_y = current_y = -1;
+//BX_INFO(("xxx: LeaveNotify x,y set to -1"));
+      break;
+
+    case MapNotify:
+      /* screen needs redraw, since X would have tossed previous
+       * requests before window mapped
+       */
+//BX_INFO(("xxx: mapnotify: found"));
+      //retval = 1;
+      break;
+
+    default:
+         // (mch) Ignore...
+         BX_DEBUG(("XXX: default Xevent type"));
+      /* all events selected by StructureNotifyMask are thrown away here,
+       * since nothing is done with them */
+      break;
+    } /* end switch */
+  } /* end while */
+
+  if (mouse_update) {
+    BX_DEBUG(("XXX: bottom, send status"));
+    send_keyboard_mouse_status();
+    }
+}
+
+
+  void
+send_keyboard_mouse_status(void)
+{
+       BX_DEBUG(("XXX: prev=(%d,%d) curr=(%d,%d)",
+                       prev_x, prev_y, current_x, current_y));
+
+  if ( (prev_x!=-1) && (current_x!=-1) && (prev_y!=-1) && (current_y!=-1)) {
+    int dx, dy;
+
+    // (mch) consider warping here
+    dx = current_x - prev_x - warp_dx;
+    dy = -(current_y - prev_y - warp_dy);
+    warp_cursor(warp_home_x-current_x, warp_home_y-current_y);
+
+//BX_INFO(("xxx: MOUSE_MOTION: dx=%d, dy=%d", (int) dx, (int) dy));
+    DEV_mouse_motion (dx, dy, mouse_button_state);
+    //if (warped) {
+    //  prev_x = current_x = -1;
+    //  prev_y = current_y = -1;
+    //  }
+    //else {
+      prev_x = current_x;
+      prev_y = current_y;
+    //  }
+    }
+  else {
+    if ( (current_x!=-1) && (current_y!=-1)) {
+      prev_x = current_x;
+      prev_y = current_y;
+      }
+    else {
+      prev_x = current_x = -1;
+      prev_y = current_y = -1;
+      }
+    }
+}
+
+  void
+bx_x_gui_c::flush(void)
+{
+  if (bx_x_display)
+    XFlush(bx_x_display);
+}
+
+
+  void
+xkeypress(KeySym keysym, int press_release)
+{
+  Bit32u key_event;
+
+  /* Old (no mapping) behavior */
+  if(!bx_options.keyboard.OuseMapping->get()){
+
+    // this depends on the fact that the X11 keysyms which
+    // correspond to the ascii characters space .. tilde
+    // are in consequtive order.
+    if ((keysym >= XK_space) && (keysym <= XK_asciitilde)) {
+      key_event = ascii_to_key_event[keysym - XK_space];
+      }
+    else switch (keysym) {
+      case XK_KP_1:
+#ifdef XK_KP_End
+      case XK_KP_End:
+#endif
+        key_event = BX_KEY_KP_END; break;
+
+      case XK_KP_2:
+#ifdef XK_KP_Down
+      case XK_KP_Down:
+#endif
+        key_event = BX_KEY_KP_DOWN; break;
+
+      case XK_KP_3:
+#ifdef XK_KP_Page_Down
+      case XK_KP_Page_Down:
+#endif
+        key_event = BX_KEY_KP_PAGE_DOWN; break;
+
+      case XK_KP_4:
+#ifdef XK_KP_Left
+      case XK_KP_Left:
+#endif
+        key_event = BX_KEY_KP_LEFT; break;
+
+      case XK_KP_5:
+#ifdef XK_KP_Begin
+      case XK_KP_Begin:
+#endif
+        key_event = BX_KEY_KP_5; break;
+
+      case XK_KP_6:
+#ifdef XK_KP_Right
+      case XK_KP_Right:
+#endif
+        key_event = BX_KEY_KP_RIGHT; break;
+
+      case XK_KP_7:
+#ifdef XK_KP_Home
+      case XK_KP_Home:
+#endif
+        key_event = BX_KEY_KP_HOME; break;
+
+      case XK_KP_8:
+#ifdef XK_KP_Up
+      case XK_KP_Up:
+#endif
+        key_event = BX_KEY_KP_UP; break;
+
+      case XK_KP_9:
+#ifdef XK_KP_Page_Up
+      case XK_KP_Page_Up:
+#endif
+        key_event = BX_KEY_KP_PAGE_UP; break;
+
+      case XK_KP_0:
+#ifdef XK_KP_Insert
+      case XK_KP_Insert:
+#endif
+        key_event = BX_KEY_KP_INSERT; break;
+
+      case XK_KP_Decimal:
+#ifdef XK_KP_Delete
+      case XK_KP_Delete:
+#endif
+        key_event = BX_KEY_KP_DELETE; break;
+
+#ifdef XK_KP_Enter
+      case XK_KP_Enter:    key_event = BX_KEY_KP_ENTER; break;
+#endif
+
+      case XK_KP_Subtract: key_event = BX_KEY_KP_SUBTRACT; break;
+      case XK_KP_Add:      key_event = BX_KEY_KP_ADD; break;
+
+      case XK_KP_Multiply: key_event = BX_KEY_KP_MULTIPLY; break;
+      case XK_KP_Divide:   key_event = BX_KEY_KP_DIVIDE; break;
+
+
+      case XK_Up:          key_event = BX_KEY_UP; break;
+      case XK_Down:        key_event = BX_KEY_DOWN; break;
+      case XK_Left:        key_event = BX_KEY_LEFT; break;
+      case XK_Right:       key_event = BX_KEY_RIGHT; break;
+
+
+      case XK_Delete:      key_event = BX_KEY_DELETE; break;
+      case XK_BackSpace:   key_event = BX_KEY_BACKSPACE; break;
+      case XK_Tab:         key_event = BX_KEY_TAB; break;
+#ifdef XK_ISO_Left_Tab
+      case XK_ISO_Left_Tab: key_event = BX_KEY_TAB; break;
+#endif
+      case XK_Return:      key_event = BX_KEY_ENTER; break;
+      case XK_Escape:      key_event = BX_KEY_ESC; break;
+      case XK_F1:          key_event = BX_KEY_F1; break;
+      case XK_F2:          key_event = BX_KEY_F2; break;
+      case XK_F3:          key_event = BX_KEY_F3; break;
+      case XK_F4:          key_event = BX_KEY_F4; break;
+      case XK_F5:          key_event = BX_KEY_F5; break;
+      case XK_F6:          key_event = BX_KEY_F6; break;
+      case XK_F7:          key_event = BX_KEY_F7; break;
+      case XK_F8:          key_event = BX_KEY_F8; break;
+      case XK_F9:          key_event = BX_KEY_F9; break;
+      case XK_F10:         key_event = BX_KEY_F10; break;
+      case XK_F11:         key_event = BX_KEY_F11; break;
+      case XK_F12:         key_event = BX_KEY_F12; break;
+      case XK_Control_L:   key_event = BX_KEY_CTRL_L; break;
+#ifdef XK_Control_R
+      case XK_Control_R:   key_event = BX_KEY_CTRL_R; break;
+#endif
+      case XK_Shift_L:     key_event = BX_KEY_SHIFT_L; break;
+      case XK_Shift_R:     key_event = BX_KEY_SHIFT_R; break;
+      case XK_Alt_L:       key_event = BX_KEY_ALT_L; break;
+#ifdef XK_Alt_R
+      case XK_Alt_R:       key_event = BX_KEY_ALT_R; break;
+#endif
+      case XK_Caps_Lock:   key_event = BX_KEY_CAPS_LOCK; break;
+      case XK_Num_Lock:    key_event = BX_KEY_NUM_LOCK; break;
+#ifdef XK_Scroll_Lock
+      case XK_Scroll_Lock: key_event = BX_KEY_SCRL_LOCK; break;
+#endif
+#ifdef XK_Print
+      case XK_Print:       key_event = BX_KEY_PRINT; break;
+#endif
+#ifdef XK_Pause
+      case XK_Pause:       key_event = BX_KEY_PAUSE; break;
+#endif
+
+      case XK_Insert:      key_event = BX_KEY_INSERT; break;
+      case XK_Home:        key_event = BX_KEY_HOME; break;
+      case XK_End:         key_event = BX_KEY_END; break;
+      case XK_Page_Up:     key_event = BX_KEY_PAGE_UP; break;
+      case XK_Page_Down:   key_event = BX_KEY_PAGE_DOWN; break;
+
+      default:
+        BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+        return;
+      break;
+      }
+    }
+  else {
+   /* use mapping */
+   BXKeyEntry *entry = bx_keymap.findHostKey (keysym);
+   if (!entry) {
+     BX_ERROR(( "xkeypress(): keysym %x unhandled!", (unsigned) keysym ));
+     return;
+   }
+   key_event = entry->baseKey;
+ }
+
+  if (press_release)
+    key_event |= BX_KEY_RELEASED;
+
+  DEV_kbd_gen_scancode(key_event);
+}
+
+
+  void
+bx_x_gui_c::clear_screen(void)
+{
+  XClearArea(bx_x_display, win, 0, bx_headerbar_y, dimension_x, dimension_y-bx_headerbar_y, 0);
+}
+
+
+
+
+  void
+bx_x_gui_c::text_update(Bit8u *old_text, Bit8u *new_text,
+                      unsigned long cursor_x, unsigned long cursor_y,
+                      bx_vga_tminfo_t tm_info, unsigned nrows)
+{
+  unsigned char *old_line, *new_line;
+  unsigned char cChar;
+  unsigned int curs, hchars, i, j, offset, rows, x, y, xc, yc, yc2;
+  unsigned new_foreground, new_background;
+  Bit8u cfwidth, cfheight, cfheight2, font_col, font_row, font_row2;
+  bx_bool force_update=0;
+  unsigned char cell[64];
+
+  UNUSED(nrows);
+  if (charmap_updated) {
+    BX_INFO(("charmap update. Font Height is %d",font_height));
+    for (unsigned c = 0; c<256; c++) {
+      if (char_changed[c]) {
+        XFreePixmap(bx_x_display, vgafont[c]);
+        bx_bool gfxchar = tm_info.line_graphics && ((c & 0xE0) == 0xC0);
+        j = 0;
+        memset(cell, 0, sizeof(cell));
+        for(i=0; i<font_height*2; i+=2) {
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x01)<<7);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x02)<<5);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x04)<<3);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x08)<<1);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x10)>>1);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x20)>>3);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x40)>>5);
+          cell[i] |= ((vga_charmap[(c<<5)+j] & 0x80)>>7);
+          if (gfxchar) {
+            cell[i+1] = (vga_charmap[(c<<5)+j] & 0x01);
+          }
+          j++;
+        }
+
+        vgafont[c]=XCreateBitmapFromData(bx_x_display, win, 
+                        (const char*)cell,
+                        font_width, font_height);
+            if(vgafont[c] == None)
+              BX_PANIC(("Can't create vga font [%d]", c));
+        char_changed[c] = 0;
+      }
+    }
+    force_update = 1;
+    charmap_updated = 0;
+  }
+
+  if((tm_info.h_panning != h_panning) || (tm_info.v_panning != v_panning)) {
+    force_update = 1;
+    h_panning = tm_info.h_panning;
+    v_panning = tm_info.v_panning;
+  }
+
+  // first invalidate character at previous and new cursor location
+  if ( (prev_cursor_y < text_rows) && (prev_cursor_x < text_cols) ) {
+    curs = prev_cursor_y * tm_info.line_offset + prev_cursor_x * 2;
+    old_text[curs] = ~new_text[curs];
+  }
+  if((tm_info.cs_start <= tm_info.cs_end) && (tm_info.cs_start < font_height) &&
+     (cursor_y < text_rows) && (cursor_x < text_cols)) {
+    curs = cursor_y * tm_info.line_offset + cursor_x * 2;
+    old_text[curs] = ~new_text[curs];
+  } else {
+    curs = 0xffff;
+  }
+
+  rows = text_rows;
+  if (v_panning) rows++;
+  y = 0;
+  do {
+    hchars = text_cols;
+    if (h_panning) hchars++;
+    if (v_panning) {
+      if (y == 0) {
+        yc = bx_headerbar_y;
+        font_row = v_panning;
+        cfheight = font_height - v_panning;
+      } else {
+        yc = y * font_height + bx_headerbar_y - v_panning;
+        font_row = 0;
+        if (rows == 1) {
+          cfheight = v_panning;
+        } else {
+          cfheight = font_height;
+        }
+      }
+    } else {
+      yc = y * font_height + bx_headerbar_y;
+      font_row = 0;
+      cfheight = font_height;
+    }
+    new_line = new_text;
+    old_line = old_text;
+    x = 0;
+    offset = y * tm_info.line_offset;
+    do {
+      if (h_panning) {
+        if (hchars > text_cols) {
+          xc = 0;
+          font_col = h_panning;
+          cfwidth = font_width - h_panning;
+        } else {
+          xc = x * font_width - h_panning;
+          font_col = 0;
+          if (hchars == 1) {
+            cfwidth = h_panning;
+          } else {
+            cfwidth = font_width;
+          }
+        }
+      } else {
+        xc = x * font_width;
+        font_col = 0;
+        cfwidth = font_width;
+      }
+      if ( force_update || (old_text[0] != new_text[0])
+          || (old_text[1] != new_text[1]) ) {
+
+        cChar = new_text[0];
+        new_foreground = new_text[1] & 0x0f;
+        new_background = (new_text[1] & 0xf0) >> 4;
+
+        XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+        XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+
+        XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row, cfwidth, cfheight,
+                   xc, yc, 1);
+        if (offset == curs) {
+          XSetForeground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_background)]);
+          XSetBackground(bx_x_display, gc, col_vals[DEV_vga_get_actl_pal_idx(new_foreground)]);
+          if (font_row == 0) {
+            yc2 = yc + tm_info.cs_start;
+            font_row2 = tm_info.cs_start;
+            cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+          } else {
+            if (v_panning > tm_info.cs_start) {
+              yc2 = yc;
+              font_row2 = font_row;
+              cfheight2 = tm_info.cs_end - v_panning + 1;
+            } else {
+              yc2 = yc + tm_info.cs_start - v_panning;
+              font_row2 = tm_info.cs_start;
+              cfheight2 = tm_info.cs_end - tm_info.cs_start + 1;
+            }
+          }
+          XCopyPlane(bx_x_display, vgafont[cChar], win, gc, font_col, font_row2, cfwidth,
+                     cfheight2, xc, yc2, 1);
+        }
+      }
+      x++;
+      new_text+=2;
+      old_text+=2;
+      offset+=2;
+    } while (--hchars);
+    y++;
+    new_text = new_line + tm_info.line_offset;
+    old_text = old_line + tm_info.line_offset;
+  } while (--rows);
+
+  prev_cursor_x = cursor_x;
+  prev_cursor_y = cursor_y;
+
+  XFlush(bx_x_display);
+}
+
+  int
+bx_x_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
+{
+  int len;
+  Bit8u *tmp = (Bit8u *)XFetchBytes (bx_x_display, &len);
+  // according to man XFetchBytes, tmp must be freed by XFree().  So allocate
+  // a new buffer with "new".  The keyboard code will free it with delete []
+  // when the paste is done.
+  Bit8u *buf = new Bit8u[len];
+  memcpy (buf, tmp, len);
+  *bytes = buf;
+  *nbytes = len;
+  XFree (tmp);
+  return 1;
+}
+
+  int
+bx_x_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
+{
+  // this writes data to the clipboard.
+  BX_INFO (("storing %d bytes to X windows clipboard", len));
+  XSetSelectionOwner(bx_x_display, XA_PRIMARY, None, CurrentTime);
+  XStoreBytes (bx_x_display, (char *)text_snapshot, len);
+  return 1;
+}
+
+
+  void
+bx_x_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
+{
+  unsigned x, y;
+  unsigned color, offset;
+  Bit8u b0, b1, b2, b3;
+
+  Bit16u *tile16 = (Bit16u *)tile;
+  switch (vga_bpp) {
+    case 32:  // 32 bits per pixel
+      if (ximage->byte_order == LSBFirst) {
+        memcpy(&ximage->data[0], tile, x_tilesize*y_tilesize*4);
+        }
+      else { // MSBFirst
+        for (y=0; y<y_tilesize; y++) {
+          for (x=0; x<x_tilesize; x++) {
+            offset = imWide*y + 4*x;
+            ximage->data[offset + 0] = tile[(y*x_tilesize + x)*4 + 3];
+            ximage->data[offset + 1] = tile[(y*x_tilesize + x)*4 + 2];
+            ximage->data[offset + 2] = tile[(y*x_tilesize + x)*4 + 1];
+            ximage->data[offset + 3] = tile[(y*x_tilesize + x)*4];
+            }
+          }
+        }
+      break;
+    case 24:  // 24 bits per pixel
+      for (y=0; y<y_tilesize; y++) {
+        for (x=0; x<x_tilesize; x++) {
+          switch (imBPP) {
+            case 24:  // 24 bits per pixel
+              offset = imWide*y + 3*x;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+                ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3 + 2];
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+                ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3];
+                }
+              break;
+            case 32:  // 32 bits per pixel
+              offset = imWide*y + 4*x;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = tile[(y*x_tilesize + x)*3];
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 1];
+                ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 2];
+                ximage->data[offset + 3] = 0;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = 0;
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*3 + 2];
+                ximage->data[offset + 2] = tile[(y*x_tilesize + x)*3 + 1];
+                ximage->data[offset + 3] = tile[(y*x_tilesize + x)*3];
+                }
+              break;
+            }
+          }
+        }
+      break;
+    case 16:  // 16 bits per pixel
+      for (y=0; y<y_tilesize; y++) {
+        for (x=0; x<x_tilesize; x++) {
+          switch (imBPP) {
+            case 16:  // 16 bits per pixel
+              offset = imWide*y + 2*x;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2];
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2 + 1];
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = tile[(y*x_tilesize + x)*2 + 1];
+                ximage->data[offset + 1] = tile[(y*x_tilesize + x)*2];
+                }
+              break;
+            case 24:  // 24 bits per pixel
+              offset = imWide*y + 3*x;
+              b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+              b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+              b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b2;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b0;
+                }
+              break;
+            case 32:  // 32 bits per pixel
+              offset = imWide*y + 4*x;
+              b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+              b1 = (tile16[y*x_tilesize + x] & 0x07e0) >> 3;
+              b2 = (tile16[y*x_tilesize + x] & 0xF800) >> 8;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                ximage->data[offset + 3] = 0;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = 0;
+                ximage->data[offset + 1] = b2;
+                ximage->data[offset + 2] = b1;
+                ximage->data[offset + 3] = b0;
+                }
+              break;
+            }
+          }
+        }
+      break;
+    case 15:  // 15 bits per pixel
+      for (y=0; y<y_tilesize; y++) {
+        for (x=0; x<x_tilesize; x++) {
+          switch (imBPP) {
+            case 16:  // 16 bits per pixel
+              offset = imWide*y + 2*x;
+              b0 = (tile16[y*x_tilesize + x] & 0x001f);
+              b0 |= (tile16[y*x_tilesize + x] & 0x0060) << 1;
+              b1 = (tile16[y*x_tilesize + x] & 0x7f80) >> 7;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b1;
+                ximage->data[offset + 1] = b0;
+                }
+              break;
+            case 24:  // 24 bits per pixel
+              offset = imWide*y + 3*x;
+              b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+              b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+              b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b2;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b0;
+                }
+              break;
+            case 32:  // 32 bits per pixel
+              offset = imWide*y + 4*x;
+              b0 = (tile16[y*x_tilesize + x] & 0x001f) << 3;
+              b1 = (tile16[y*x_tilesize + x] & 0x03e0) >> 2;
+              b2 = (tile16[y*x_tilesize + x] & 0x7c00) >> 7;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                ximage->data[offset + 3] = 0;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = 0;
+                ximage->data[offset + 1] = b2;
+                ximage->data[offset + 2] = b1;
+                ximage->data[offset + 3] = b0;
+                }
+              break;
+            }
+          }
+        }
+      break;
+    default:  // 8 bits per pixel
+      for (y=0; y<y_tilesize; y++) {
+        for (x=0; x<x_tilesize; x++) {
+          color = col_vals[tile[y*x_tilesize + x]];
+          switch (imBPP) {
+            case 8:  // 8 bits per pixel
+              ximage->data[imWide*y + x] = color;
+              break;
+            case 16: // 16 bits per pixel
+              offset = imWide*y + 2*x;
+              b0 = color >> 0;
+              b1 = color >> 8;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b1;
+                ximage->data[offset + 1] = b0;
+                }
+              break;
+            case 24: // 24 bits per pixel
+              offset = imWide*y + 3*x;
+              b0 = color >> 0;
+              b1 = color >> 8;
+              b2 = color >> 16;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b2;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b0;
+                }
+              break;
+            case 32: // 32 bits per pixel
+              offset = imWide*y + 4*x;
+              b0 = color >> 0;
+              b1 = color >> 8;
+              b2 = color >> 16;
+              b3 = color >> 24;
+              if (ximage->byte_order == LSBFirst) {
+                ximage->data[offset + 0] = b0;
+                ximage->data[offset + 1] = b1;
+                ximage->data[offset + 2] = b2;
+                ximage->data[offset + 3] = b3;
+                }
+              else { // MSBFirst
+                ximage->data[offset + 0] = b3;
+                ximage->data[offset + 1] = b2;
+                ximage->data[offset + 2] = b1;
+                ximage->data[offset + 3] = b0;
+                }
+              break;
+            default:
+              BX_PANIC(("X_graphics_tile_update: bits_per_pixel %u not implemented",
+                (unsigned) imBPP));
+              break;
+            }
+          }
+        }
+    }
+  XPutImage(bx_x_display, win, gc, ximage, 0, 0, x0, y0+bx_headerbar_y,
+            x_tilesize, y_tilesize);
+}
+
+
+  bx_bool
+bx_x_gui_c::palette_change(unsigned index, unsigned red, unsigned green, unsigned blue)
+{
+  // returns: 0=no screen update needed (color map change has direct effect)
+  //          1=screen updated needed (redraw using current colormap)
+  XColor color;
+
+  color.flags = DoRed | DoGreen | DoBlue;
+  color.red   = red << 8;
+  color.green = green << 8;
+  color.blue  = blue << 8;
+
+  if (bx_options.Oprivate_colormap->get ()) {
+    color.pixel = index;
+    XStoreColor(bx_x_display, default_cmap, &color);
+    return(0); // no screen update needed
+    }
+  else {
+    XAllocColor(bx_x_display, DefaultColormap(bx_x_display, bx_x_screen_num),
+                &color);
+    col_vals[index] = color.pixel;
+    return(1); // screen update needed
+    }
+}
+
+
+  void
+bx_x_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
+{
+  if ((bpp <= imBPP) && ((bpp == 8) || (bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32))) {
+    vga_bpp = bpp;
+  } else {
+    BX_PANIC(("%d bpp graphics mode not supported", bpp));
+  }
+  if (fheight > 0) {
+    font_height = fheight;
+    font_width = fwidth;
+    text_cols = x / font_width;
+    text_rows = y / font_height;
+  }
+  if ( (x != dimension_x) || (y != (dimension_y-bx_headerbar_y)) ) {
+    XSizeHints hints;
+    long supplied_return;
+
+    if ( XGetWMNormalHints(bx_x_display, win, &hints, &supplied_return) &&
+         supplied_return & PMaxSize ) {
+      hints.max_width = hints.min_width = x;
+      hints.max_height = hints.min_height = y+bx_headerbar_y;
+      XSetWMNormalHints(bx_x_display, win, &hints);
+      }
+    XResizeWindow(bx_x_display, win, x, y+bx_headerbar_y);
+    dimension_x = x;
+    dimension_y = y + bx_headerbar_y;
+    }
+}
+
+
+  void
+bx_x_gui_c::show_headerbar(void)
+{
+  unsigned xorigin;
+  int xleft, xright;
+
+  // clear header bar area to white
+  XFillRectangle(bx_x_display, win, gc_headerbar_inv, 0,0, dimension_x, bx_headerbar_y);
+
+  xleft = 0;
+  xright = dimension_x;
+  for (unsigned i=0; i<bx_headerbar_entries; i++) {
+    if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT) {
+      xorigin = bx_headerbar_entry[i].xorigin;
+      xleft += bx_headerbar_entry[i].xdim;
+      }
+    else {
+      xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+      xright = xorigin;
+      }
+    if (xright < xleft) break;
+    XCopyPlane(bx_x_display, bx_headerbar_entry[i].bitmap, win, gc_headerbar,
+      0,0, bx_headerbar_entry[i].xdim, bx_headerbar_entry[i].ydim,
+              xorigin, 0, 1);
+    }
+}
+
+
+  unsigned
+bx_x_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
+{
+  if (bx_bitmap_entries >= BX_MAX_PIXMAPS) {
+    BX_PANIC(("x: too many pixmaps, increase BX_MAX_PIXMAPS"));
+    }
+
+  bx_bitmaps[bx_bitmap_entries].bmap =
+    XCreateBitmapFromData(bx_x_display, win, (const char *) bmap, xdim, ydim);
+  bx_bitmaps[bx_bitmap_entries].xdim = xdim;
+  bx_bitmaps[bx_bitmap_entries].ydim = ydim;
+  if (!bx_bitmaps[bx_bitmap_entries].bmap) {
+    BX_PANIC(("x: could not create bitmap"));
+    }
+  bx_bitmap_entries++;
+  return(bx_bitmap_entries-1); // return index as handle
+}
+
+
+  unsigned
+bx_x_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
+{
+  unsigned hb_index;
+
+  if ( (bx_headerbar_entries+1) > BX_MAX_HEADERBAR_ENTRIES )
+    BX_PANIC(("x: too many headerbar entries, increase BX_MAX_HEADERBAR_ENTRIES"));
+
+  bx_headerbar_entries++;
+  hb_index = bx_headerbar_entries - 1;
+
+  bx_headerbar_entry[hb_index].bitmap = bx_bitmaps[bmap_id].bmap;
+  bx_headerbar_entry[hb_index].xdim   = bx_bitmaps[bmap_id].xdim;
+  bx_headerbar_entry[hb_index].ydim   = bx_bitmaps[bmap_id].ydim;
+  bx_headerbar_entry[hb_index].alignment = alignment;
+  bx_headerbar_entry[hb_index].f = f;
+  if (alignment == BX_GRAVITY_LEFT) {
+    bx_headerbar_entry[hb_index].xorigin = bx_bitmap_left_xorigin;
+    bx_headerbar_entry[hb_index].yorigin = 0;
+    bx_bitmap_left_xorigin += bx_bitmaps[bmap_id].xdim;
+    }
+  else { // BX_GRAVITY_RIGHT
+    bx_bitmap_right_xorigin += bx_bitmaps[bmap_id].xdim;
+    bx_headerbar_entry[hb_index].xorigin = bx_bitmap_right_xorigin;
+    bx_headerbar_entry[hb_index].yorigin = 0;
+    }
+  return(hb_index);
+}
+
+  void
+bx_x_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
+{
+  unsigned xorigin;
+
+  bx_headerbar_entry[hbar_id].bitmap = bx_bitmaps[bmap_id].bmap;
+
+  if (bx_headerbar_entry[hbar_id].alignment == BX_GRAVITY_LEFT)
+    xorigin = bx_headerbar_entry[hbar_id].xorigin;
+  else
+    xorigin = dimension_x - bx_headerbar_entry[hbar_id].xorigin;
+  XCopyPlane(bx_x_display, bx_headerbar_entry[hbar_id].bitmap, win, gc_headerbar,
+    0,0, bx_headerbar_entry[hbar_id].xdim, bx_headerbar_entry[hbar_id].ydim,
+            xorigin, 0, 1);
+}
+
+
+  void
+headerbar_click(int x, int y)
+{
+  int xorigin;
+
+  // assuming y is in bounds
+  UNUSED(y);
+  for (unsigned i=0; i<bx_headerbar_entries; i++) {
+    if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT)
+      xorigin = bx_headerbar_entry[i].xorigin;
+    else
+      xorigin = dimension_x - bx_headerbar_entry[i].xorigin;
+    if ( (x>=xorigin) && (x<(xorigin+int(bx_headerbar_entry[i].xdim))) ) {
+      bx_headerbar_entry[i].f();
+      return;
+      }
+    }
+}
+
+  void
+bx_x_gui_c::exit(void)
+{
+  if (!x_init_done) return;
+
+  // Delete the font bitmaps
+  for (int i=0; i<256; i++) {
+    //if (vgafont[i] != NULL) 
+      XFreePixmap(bx_x_display,vgafont[i]);
+  }
+
+  if (bx_x_display)
+    XCloseDisplay (bx_x_display);
+  BX_INFO(("Exit."));
+}
+
+static void warp_cursor (int dx, int dy)
+{
+      if (bx_options.Omouse_enabled->get () &&
+         (warp_dx || warp_dy || dx || dy)
+         ) {
+           warp_dx = dx;
+           warp_dy = dy;
+           XWarpPointer(bx_x_display, None, None, 0, 0, 0, 0, dx, dy);
+      }
+}
+
+static void disable_cursor ()
+{
+      static Cursor cursor;
+      static unsigned cursor_created = 0;
+
+      static int shape_width = 16,
+            shape_height = 16,
+            mask_width = 16,
+            mask_height = 16;
+
+      static uint32 shape_bits[(16*16)/32] = {
+           0x00000000, 0x00000000, 0x00000000, 0x00000000,
+           0x00000000, 0x00000000, 0x00000000, 0x00000000,
+      };
+      static uint32 mask_bits[(16*16)/32] = {
+           0x00000000, 0x00000000, 0x00000000, 0x00000000,
+           0x00000000, 0x00000000, 0x00000000, 0x00000000,
+      };
+
+      if (!cursor_created) {
+           Pixmap shape, mask;
+           XColor white, black;
+           shape = XCreatePixmapFromBitmapData(bx_x_display,
+                                               RootWindow(bx_x_display,bx_x_screen_num),
+                                               (char*)shape_bits,
+                                               shape_width,
+                                               shape_height,
+                                               1, 0, 1);
+           mask =  XCreatePixmapFromBitmapData(bx_x_display,
+                                               RootWindow(bx_x_display,bx_x_screen_num),
+                                               (char*)mask_bits,
+                                               mask_width,
+                                               mask_height,
+                                               1, 0, 1);
+           XParseColor(bx_x_display, default_cmap, "black", &black);
+           XParseColor(bx_x_display, default_cmap, "white", &white);
+           cursor = XCreatePixmapCursor(bx_x_display, shape, mask,
+                                        &white, &black, 1, 1);
+           cursor_created = 1;
+      }
+
+      XDefineCursor(bx_x_display, win, cursor);
+}
+
+static void enable_cursor ()
+{
+      XUndefineCursor(bx_x_display, win);
+}
+
+/* convertStringToXKeysym is a keymap callback
+ * used when reading the keymap file.
+ * It converts a Symblic String to a GUI Constant
+ *
+ * It returns a Bit32u constant or BX_KEYMAP_UNKNOWN if it fails
+ */
+static Bit32u convertStringToXKeysym (const char *string)
+{
+    if (strncmp ("XK_", string, 3) != 0)
+      return BX_KEYMAP_UNKNOWN;
+    KeySym keysym=XStringToKeysym(string+3);
+
+    // failure, return unknown
+    if(keysym==NoSymbol) return BX_KEYMAP_UNKNOWN;
+
+    return((Bit32u)keysym);
+}
+
+#if BX_USE_IDLE_HACK
+
+/* BX_USE_IDLE_HACK: a small idle hack by
+ * Roland.Mainz@informatik.med.uni-giessen.de to prevent bochs
+ * from consuming 100% CPU time even when it is not required (for
+ * example, the OS in the emulator calls HLT to wait for an interupt)
+ * pro:
+ * - no more 100% CPU usage
+ * contra:
+ * - we're sleeping too long
+ * - bochs still consumes ~10%-20% CPU time while executing an idle 
+ *   linux kernel
+ * - this is an hack
+ */
+
+/* XPeekEvent() with timeout 
+ * (adopted from mozilla/gfx/src/xprint/xprintutil_printtofile.c#XNextEventTimeout())
+ */
+static
+Bool XPeekEventTimeout( Display *display, XEvent *event_return, struct timeval *timeout ) 
+{
+    int      res;
+    fd_set   readfds;
+    int      display_fd = XConnectionNumber(display);
+
+    /* small shortcut... */
+    if( timeout == NULL )
+    {
+      XPeekEvent(display, event_return);
+      return(True);
+    }
+    
+    FD_ZERO(&readfds);
+    FD_SET(display_fd, &readfds);
+
+    /* Note/bug: In the case of internal X events (like used to trigger callbacks 
+     * registered by XpGetDocumentData()&co.) select() will return with "new info" 
+     * - but XNextEvent() below processes these _internal_ events silently - and 
+     * will block if there are no other non-internal events.
+     * The workaround here is to check with XEventsQueued() if there are non-internal 
+     * events queued - if not select() will be called again - unfortunately we use 
+     * the old timeout here instead of the "remaining" time... (this only would hurt 
+     * if the timeout would be really long - but for current use with values below
+     * 1/2 secs it does not hurt... =:-)
+     */
+    while( XEventsQueued(display, QueuedAfterFlush) == 0 )
+    {
+      res = select(display_fd+1, &readfds, NULL, NULL, timeout);
+    
+      switch(res)
+      {
+        case -1: /* select() error - should not happen */ 
+            perror("XPeekEventTimeout: select() failure"); 
+            return(False);
+        case  0: /* timeout */
+          return(False);
+      }
+    }
+    
+    XPeekEvent(display, event_return); 
+    return(True);
+}
+
+#if BX_USE_IDLE_HACK
+void bx_x_gui_c::sim_is_idle () {
+  XEvent dummy;
+  struct timeval   timeout;   
+  timeout.tv_sec  = 0;
+  timeout.tv_usec = 1000; /* 1/1000 s */  
+  XPeekEventTimeout(bx_x_display, &dummy, &timeout);
+}
+#endif
+#endif /* BX_USE_IDLE_HACK */  
+
+#endif /* if BX_WITH_X11 */
diff --git a/tools/ioemu/include/bochs.h b/tools/ioemu/include/bochs.h
new file mode 100644 (file)
index 0000000..59b3067
--- /dev/null
@@ -0,0 +1,771 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: bochs.h,v 1.128.2.1 2004/02/06 22:14:25 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// bochs.h is the master header file for all C++ code.  It includes all 
+// the system header files needed by bochs, and also includes all the bochs
+// C++ header files.  Because bochs.h and the files that it includes has 
+// structure and class definitions, it cannot be called from C code.
+// 
+
+#ifndef BX_BOCHS_H
+#  define BX_BOCHS_H 1
+
+#include "config.h"      /* generated by configure script from config.h.in */
+
+extern "C" {
+
+#ifdef WIN32
+// In a win32 compile (including cygwin), windows.h is required for several
+// files in gui and iodev.  It is important to include it here in a header
+// file so that WIN32-specific data types can be used in fields of classes.
+#include <windows.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#ifndef WIN32
+#  include <unistd.h>
+#else
+#  include <io.h>
+#endif
+#include <time.h>
+#if BX_WITH_MACOS
+#define Float32 KLUDGE_Float32
+#define Float64 KLUDGE_Float64
+#  include <types.h>
+#undef Float32
+#undef Float64
+#  include <stat.h>
+#  include <cstdio>
+#  include <unistd.h>
+#elif BX_WITH_CARBON
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  include <sys/param.h> /* for MAXPATHLEN */
+#  include <utime.h>
+#else
+#  ifndef WIN32
+#    include <sys/time.h>
+#  endif
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#endif
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef macintosh
+#  define SuperDrive "[fd:]"
+#endif
+}
+
+#include "osdep.h"       /* platform dependent includes and defines */ 
+#include "bxversion.h"
+
+#include "gui/siminterface.h"
+
+// prototypes
+int bx_begin_simulation (int argc, char *argv[]);
+
+//
+// some macros to interface the CPU and memory to external environment
+// so that these functions can be redirected to the debugger when
+// needed.
+//
+
+#if ((BX_DEBUGGER == 1) && (BX_NUM_SIMULATORS >= 2))
+// =-=-=-=-=-=-=- Redirected to cosimulation debugger -=-=-=-=-=-=-=
+#define DEV_vga_mem_read(addr)       bx_dbg_ucmem_read(addr)
+#define DEV_vga_mem_write(addr, val) bx_dbg_ucmem_write(addr, val)
+
+#if BX_SUPPORT_A20
+#  define A20ADDR(x)               ( (x) & bx_pc_system.a20_mask )
+#else
+#  define A20ADDR(x)                (x)
+#endif
+#define BX_INP(addr, len)           bx_dbg_inp(addr, len)
+#define BX_OUTP(addr, val, len)     bx_dbg_outp(addr, val, len)
+#define BX_HRQ                      (bx_pc_system.HRQ)
+#define BX_RAISE_HLDA()             bx_dbg_raise_HLDA()
+#define BX_TICK1()
+#define BX_INTR                     bx_pc_system.INTR
+#define BX_SET_INTR(b)              bx_dbg_set_INTR(b)
+#if BX_SIM_ID == 0
+#  define BX_CPU_C                  bx_cpu0_c
+#  define BX_CPU                    bx_cpu0
+#  define BX_MEM_C                  bx_mem0_c
+#  define BX_MEM                    bx_mem0
+#else
+#  define BX_CPU_C                  bx_cpu1_c
+#  define BX_CPU                    bx_cpu1
+#  define BX_MEM_C                  bx_mem1_c
+#  define BX_MEM                    bx_mem1
+#endif
+#define BX_SET_ENABLE_A20(enabled)  bx_dbg_async_pin_request(BX_DBG_ASYNC_PENDING_A20, \
+                                      enabled)
+#define BX_GET_ENABLE_A20()         bx_pc_system.get_enable_a20()
+#error FIXME: cosim mode not fixed yet
+
+#else
+
+// =-=-=-=-=-=-=- Normal optimized use -=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#if BX_SUPPORT_A20
+#  define A20ADDR(x)               ( (x) & bx_pc_system.a20_mask )
+#else
+#  define A20ADDR(x)               (x)
+#endif
+//
+// some pc_systems functions just redirect to the IO devices so optimize
+// by eliminating call here
+//
+// #define BX_INP(addr, len)        bx_pc_system.inp(addr, len)
+// #define BX_OUTP(addr, val, len)  bx_pc_system.outp(addr, val, len)
+#define BX_INP(addr, len)           bx_devices.inp(addr, len)
+#define BX_OUTP(addr, val, len)     bx_devices.outp(addr, val, len)
+#define BX_TICK1()                  bx_pc_system.tick1()
+#define BX_TICKN(n)                 bx_pc_system.tickn(n)
+#define BX_INTR                     bx_pc_system.INTR
+#define BX_SET_INTR(b)              bx_pc_system.set_INTR(b)
+#define BX_CPU_C                    bx_cpu_c
+#define BX_MEM_C                    bx_mem_c
+#define BX_HRQ                      (bx_pc_system.HRQ)
+#define BX_MEM_READ_PHYSICAL(phy_addr, len, ptr) \
+  BX_MEM(0)->readPhysicalPage(BX_CPU(0), phy_addr, len, ptr)
+#define BX_MEM_WRITE_PHYSICAL(phy_addr, len, ptr) \
+  BX_MEM(0)->writePhysicalPage(BX_CPU(0), phy_addr, len, ptr)
+
+#if BX_SMP_PROCESSORS==1
+#define BX_CPU(x)                   (&bx_cpu)
+#define BX_MEM(x)                   (&bx_mem)
+#else
+#define BX_CPU(x)                   (bx_cpu_array[x])
+#define BX_MEM(x)                   (bx_mem_array[x])
+#endif
+
+#define BX_SET_ENABLE_A20(enabled)  bx_pc_system.set_enable_a20(enabled)
+#define BX_GET_ENABLE_A20()         bx_pc_system.get_enable_a20()
+
+#endif
+
+
+// you can't use static member functions on the CPU, if there are going
+// to be 2 cpus.  Check this early on.
+#if (BX_SMP_PROCESSORS>1)
+#  if (BX_USE_CPU_SMF!=0)
+#    error For SMP simulation, BX_USE_CPU_SMF must be 0.
+#  endif
+#endif
+
+
+// #define BX_IAC()                 bx_pc_system.IAC()
+//#define BX_IAC()                    bx_dbg_IAC()
+
+//
+// Ways for the the external environment to report back information
+// to the debugger.
+//
+
+#if BX_DEBUGGER
+#  define BX_DBG_ASYNC_INTR bx_guard.async.irq
+#  define BX_DBG_ASYNC_DMA  bx_guard.async.dma
+#if (BX_NUM_SIMULATORS > 1)
+// for multiple simulators, we always need this info, since we're
+// going to replay it.
+#  define BX_DBG_DMA_REPORT(addr, len, what, val) \
+        bx_dbg_dma_report(addr, len, what, val)
+#  define BX_DBG_IAC_REPORT(vector, irq) \
+        bx_dbg_iac_report(vector, irq)
+#  define BX_DBG_A20_REPORT(val) \
+        bx_dbg_a20_report(val)
+#  define BX_DBG_IO_REPORT(addr, size, op, val) \
+        bx_dbg_io_report(addr, size, op, val)
+#  define BX_DBG_UCMEM_REPORT(addr, size, op, val)
+#else
+// for a single simulator debug environment, we can optimize a little
+// by conditionally calling, as per requested.
+
+#  define BX_DBG_DMA_REPORT(addr, len, what, val) \
+        if (bx_guard.report.dma) bx_dbg_dma_report(addr, len, what, val)
+#  define BX_DBG_IAC_REPORT(vector, irq) \
+        if (bx_guard.report.irq) bx_dbg_iac_report(vector, irq)
+#  define BX_DBG_A20_REPORT(val) \
+        if (bx_guard.report.a20) bx_dbg_a20_report(val)
+#  define BX_DBG_IO_REPORT(addr, size, op, val) \
+        if (bx_guard.report.io) bx_dbg_io_report(addr, size, op, val)
+#  define BX_DBG_UCMEM_REPORT(addr, size, op, val) \
+        if (bx_guard.report.ucmem) bx_dbg_ucmem_report(addr, size, op, val)
+#endif  // #if (BX_NUM_SIMULATORS > 1)
+
+#else  // #if BX_DEBUGGER
+// debugger not compiled in, use empty stubs
+#  define BX_DBG_ASYNC_INTR 1
+#  define BX_DBG_ASYNC_DMA  1
+#  define BX_DBG_DMA_REPORT(addr, len, what, val)
+#  define BX_DBG_IAC_REPORT(vector, irq)
+#  define BX_DBG_A20_REPORT(val)
+#  define BX_DBG_IO_REPORT(addr, size, op, val)
+#  define BX_DBG_UCMEM_REPORT(addr, size, op, val)
+#endif  // #if BX_DEBUGGER
+
+#define MAGIC_LOGNUM 0x12345678
+
+typedef class BOCHSAPI logfunctions {
+       char *prefix;
+       int type;
+// values of onoff: 0=ignore, 1=report, 2=ask, 3=fatal
+#define ACT_IGNORE 0
+#define ACT_REPORT 1
+#define ACT_ASK    2
+#define ACT_FATAL  3
+#define N_ACT      4
+       int onoff[N_LOGLEV];
+       class iofunctions *logio;
+       // default log actions for all devices, declared and initialized
+       // in logio.cc.
+       BOCHSAPI_CYGONLY static int default_onoff[N_LOGLEV];
+public:
+       logfunctions(void);
+       logfunctions(class iofunctions *);
+       ~logfunctions(void);
+
+       void info(const char *fmt, ...)   BX_CPP_AttrPrintf(2, 3);
+       void error(const char *fmt, ...)  BX_CPP_AttrPrintf(2, 3);
+       void panic(const char *fmt, ...)  BX_CPP_AttrPrintf(2, 3);
+       void pass(const char *fmt, ...)   BX_CPP_AttrPrintf(2, 3);
+       void ldebug(const char *fmt, ...) BX_CPP_AttrPrintf(2, 3);
+       void fatal (const char *prefix, const char *fmt, va_list ap, int exit_status);
+#if BX_EXTERNAL_DEBUGGER
+       virtual void ask (int level, const char *prefix, const char *fmt, va_list ap);
+#else
+       void ask (int level, const char *prefix, const char *fmt, va_list ap);
+#endif
+       void put(char *);
+       void settype(int);
+       void setio(class iofunctions *);
+       void setonoff(int loglev, int value) {
+         assert (loglev >= 0 && loglev < N_LOGLEV);
+         onoff[loglev] = value; 
+       }
+       char *getprefix () { return prefix; }
+       int getonoff(int level) {
+         assert (level>=0 && level<N_LOGLEV);
+         return onoff[level]; 
+        }
+       static void set_default_action (int loglev, int action) {
+         assert (loglev >= 0 && loglev < N_LOGLEV);
+         assert (action >= 0 && action < N_ACT);
+         default_onoff[loglev] = action;
+       }
+       static int get_default_action (int loglev) {
+         assert (loglev >= 0 && loglev < N_LOGLEV);
+         return default_onoff[loglev];
+       }
+} logfunc_t;
+
+#define BX_LOGPREFIX_SIZE 51
+
+enum {
+  IOLOG=0, FDLOG, GENLOG, CMOSLOG, CDLOG, DMALOG, ETHLOG, G2HLOG, HDLOG, KBDLOG,
+  NE2KLOG, PARLOG, PCILOG, PICLOG, PITLOG, SB16LOG, SERLOG, VGALOG,
+  STLOG, // state_file.cc 
+  DEVLOG, MEMLOG, DISLOG, GUILOG, IOAPICLOG, APICLOG, CPU0LOG, CPU1LOG,
+  CPU2LOG, CPU3LOG, CPU4LOG, CPU5LOG, CPU6LOG, CPU7LOG, CPU8LOG, CPU9LOG,
+  CPU10LOG, CPU11LOG, CPU12LOG, CPU13LOG, CPU14LOG, CPU15LOG, CTRLLOG,
+  UNMAPLOG, SERRLOG, BIOSLOG, PIT81LOG, PIT82LOG, IODEBUGLOG, PCI2ISALOG,
+  PLUGINLOG, EXTFPUIRQLOG , PCIVGALOG, PCIUSBLOG, VTIMERLOG, STIMERLOG
+};
+
+class BOCHSAPI iofunctions {
+       int magic;
+       char logprefix[BX_LOGPREFIX_SIZE];
+       FILE *logfd;
+       class logfunctions *log;
+       void init(void);
+       void flush(void);
+
+// Log Class types
+public:
+       iofunctions(void);
+       iofunctions(FILE *);
+       iofunctions(int);
+       iofunctions(const char *);
+       ~iofunctions(void);
+
+       void out(int facility, int level, const char *pre, const char *fmt, va_list ap);
+
+       void init_log(const char *fn);
+       void init_log(int fd);
+       void init_log(FILE *fs);
+       void set_log_prefix(const char *prefix);
+       int get_n_logfns () { return n_logfn; }
+       logfunc_t *get_logfn (int index) { return logfn_list[index]; }
+       void add_logfn (logfunc_t *fn);
+       void set_log_action (int loglevel, int action);
+       const char *getlevel(int i) {
+               static const char *loglevel[N_LOGLEV] = {
+                       "DEBUG",
+                       "INFO",
+                       "ERROR",
+                       "PANIC",
+                       "PASS"
+               };
+                if (i>=0 && i<N_LOGLEV) return loglevel[i];
+                else return "?";
+       }
+       char *getaction(int i) {
+          static char *name[] = { "ignore", "report", "ask", "fatal" };
+          assert (i>=ACT_IGNORE && i<N_ACT);
+          return name[i];
+       }
+
+protected:
+       int n_logfn;
+#define MAX_LOGFNS 128
+       logfunc_t *logfn_list[MAX_LOGFNS];
+       char *logfn;
+
+
+};
+
+typedef class BOCHSAPI iofunctions iofunc_t;
+
+
+#define SAFE_GET_IOFUNC() \
+  ((io==NULL)? (io=new iofunc_t("/dev/stderr")) : io)
+#define SAFE_GET_GENLOG() \
+  ((genlog==NULL)? (genlog=new logfunc_t(SAFE_GET_IOFUNC())) : genlog)
+/* #define NO_LOGGING */
+#ifndef NO_LOGGING
+
+#define BX_INFO(x)  (LOG_THIS info) x
+#define BX_DEBUG(x) (LOG_THIS ldebug) x
+#define BX_ERROR(x) (LOG_THIS error) x
+#define BX_PANIC(x) (LOG_THIS panic) x
+#define BX_PASS(x) (LOG_THIS pass) x
+
+#else
+
+#define EMPTY do { } while(0)
+
+#define BX_INFO(x)  EMPTY
+#define BX_DEBUG(x) EMPTY
+#define BX_ERROR(x) EMPTY
+#define BX_PANIC(x) (LOG_THIS panic) x
+#define BX_PASS(x) (LOG_THIS pass) x
+
+#endif
+
+BOCHSAPI extern iofunc_t *io;
+BOCHSAPI extern logfunc_t *genlog;
+
+#include "state_file.h"
+
+#ifndef UNUSED
+#  define UNUSED(x) ((void)x)
+#endif
+
+#define uint8   Bit8u
+#define uint16  Bit16u
+#define uint32  Bit32u
+
+#ifdef BX_USE_VMX
+extern "C" {
+#include "xc.h"
+}
+
+extern void *shared_page;
+BOCHSAPI extern int xc_handle;
+#endif
+
+#if BX_PROVIDE_CPU_MEMORY==1
+#  include "cpu/cpu.h"
+#endif
+
+#if BX_EXTERNAL_DEBUGGER
+#  include "cpu/extdb.h"
+#endif
+
+#if BX_GDBSTUB
+// defines for GDB stub
+void bx_gdbstub_init(int argc, char* argv[]);
+int bx_gdbstub_check(unsigned int eip);
+#define GDBSTUB_STOP_NO_REASON   (0xac0)
+
+#if BX_SMP_PROCESSORS!=1
+#error GDB stub was written for single processor support.  If multiprocessor support is added, then we can remove this check.
+// The big problem is knowing which CPU gdb is referring to.  In other words,
+// what should we put for "n" in BX_CPU(n)->dbg_xlate_linear2phy() and
+// BX_CPU(n)->dword.eip, etc.
+#endif
+
+#endif
+
+#if BX_DISASM
+#  include "disasm/disasm.h"
+#endif
+
+typedef struct {
+  bx_bool floppy;
+  bx_bool keyboard;
+  bx_bool video;
+  bx_bool disk;
+  bx_bool pit;
+  bx_bool pic;
+  bx_bool bios;
+  bx_bool cmos;
+  bx_bool a20;
+  bx_bool interrupts;
+  bx_bool exceptions;
+  bx_bool unsupported;
+  bx_bool temp;
+  bx_bool reset;
+  bx_bool debugger;
+  bx_bool mouse;
+  bx_bool io;
+  bx_bool xms;
+  bx_bool v8086;
+  bx_bool paging;
+  bx_bool creg;
+  bx_bool dreg;
+  bx_bool dma;
+  bx_bool unsupported_io;
+  bx_bool serial;
+  bx_bool cdrom;
+#ifdef MAGIC_BREAKPOINT
+  bx_bool magic_break_enabled;
+#endif /* MAGIC_BREAKPOINT */
+#if BX_SUPPORT_APIC
+  bx_bool apic;
+  bx_bool ioapic;
+#endif
+#if BX_DEBUG_LINUX
+  bx_bool linux_syscall;
+#endif
+  void* record_io;
+  } bx_debug_t;
+
+#define BX_ASSERT(x) do {if (!(x)) BX_PANIC(("failed assertion \"%s\" at %s:%d\n", #x, __FILE__, __LINE__));} while (0)
+void bx_signal_handler (int signum);
+int bx_atexit(void);
+BOCHSAPI extern bx_debug_t bx_dbg;
+
+
+
+/* Already in gui/siminterface.h ??? 
+#define BX_FLOPPY_NONE   10 // floppy not present
+#define BX_FLOPPY_1_2    11 // 1.2M  5.25"
+#define BX_FLOPPY_1_44   12 // 1.44M 3.5"
+#define BX_FLOPPY_2_88   13 // 2.88M 3.5"
+#define BX_FLOPPY_720K   14 // 720K  3.5"
+#define BX_FLOPPY_360K   15 // 360K  5.25"
+#define BX_FLOPPY_LAST   15 // last one
+*/
+
+
+#define BX_READ    0
+#define BX_WRITE   1
+#define BX_RW      2
+
+
+
+
+
+#include "memory/memory.h"
+
+
+enum PCS_OP { PCS_CLEAR, PCS_SET, PCS_TOGGLE };
+
+#include "pc_system.h"
+#include "plugin.h"
+#include "gui/gui.h"
+#include "gui/textconfig.h"
+#include "gui/keymap.h"
+#include "iodev/iodev.h"
+
+
+
+
+
+
+
+/* --- EXTERNS --- */
+
+#if ( BX_PROVIDE_DEVICE_MODELS==1 )
+BOCHSAPI extern bx_devices_c   bx_devices;
+#endif
+
+#if BX_GUI_SIGHANDLER
+extern bx_bool bx_gui_sighandler;
+#endif
+
+// This value controls how often each I/O device's periodic() method
+// gets called.  The timer is set up in iodev/devices.cc.
+#define BX_IODEV_HANDLER_PERIOD 100    // microseconds
+//#define BX_IODEV_HANDLER_PERIOD 10    // microseconds
+
+char *bx_find_bochsrc (void);
+int bx_parse_cmdline (int arg, int argc, char *argv[]);
+int bx_read_configuration (char *rcfile);
+int bx_write_configuration (char *rcfile, int overwrite);
+void bx_reset_options (void);
+
+#define BX_PATHNAME_LEN 512
+
+typedef struct {
+  bx_param_bool_c *Opresent;
+  bx_param_num_c *Oioaddr1;
+  bx_param_num_c *Oioaddr2;
+  bx_param_num_c *Oirq;
+  } bx_ata_options;
+
+typedef struct {
+  bx_param_string_c *Opath;
+  bx_param_num_c *Oaddress;
+  } bx_rom_options;
+
+typedef struct {
+  bx_param_string_c *Opath;
+  } bx_vgarom_options;
+
+typedef struct {
+  bx_param_num_c *Osize;
+  } bx_mem_options;
+
+typedef struct {
+  bx_param_bool_c *Oenabled;
+  bx_param_string_c *Ooutfile;
+} bx_parport_options;
+
+typedef struct {
+  bx_param_string_c *Opath;
+  bx_param_bool_c *OcmosImage;
+  } bx_cmos_options;
+
+typedef struct {
+  bx_param_num_c   *Otime0;
+  bx_param_enum_c  *Osync;
+  } bx_clock_options;
+
+typedef struct {
+  bx_param_bool_c *Opresent;
+  bx_param_num_c *Oioaddr;
+  bx_param_num_c *Oirq;
+  bx_param_string_c *Omacaddr;
+  bx_param_enum_c *Oethmod;
+  bx_param_string_c *Oethdev;
+  bx_param_string_c *Oscript;
+  } bx_ne2k_options;
+
+typedef struct {
+// These options are used for a special hack to load a
+// 32bit OS directly into memory, so it can be run without
+// any of the 16bit real mode or BIOS assistance.  This
+// is for the development of plex86, so we don't have
+// to implement real mode up front.
+  bx_param_num_c *OwhichOS;
+  bx_param_string_c *Opath;
+  bx_param_string_c *Oiolog;
+  bx_param_string_c *Oinitrd;
+  } bx_load32bitOSImage_t;
+
+typedef struct {
+  bx_param_string_c *Ofilename;
+  bx_param_string_c *Oprefix;
+  bx_param_string_c *Odebugger_filename;
+} bx_log_options;
+
+typedef struct {
+  bx_param_bool_c *Opresent;
+  bx_param_string_c *Omidifile;
+  bx_param_string_c *Owavefile;
+  bx_param_string_c *Ologfile;
+  bx_param_num_c *Omidimode;
+  bx_param_num_c *Owavemode;
+  bx_param_num_c *Ologlevel;
+  bx_param_num_c *Odmatimer;
+  } bx_sb16_options;
+
+typedef struct {
+  unsigned int port;
+  unsigned int text_base;
+  unsigned int data_base;
+  unsigned int bss_base;
+  } bx_gdbstub_t;
+
+typedef struct {
+  bx_param_bool_c *OuseMapping;
+  bx_param_string_c *Okeymap;
+  } bx_keyboard_options;
+
+#define BX_KBD_XT_TYPE        0
+#define BX_KBD_AT_TYPE        1
+#define BX_KBD_MF_TYPE        2 
+
+#define BX_N_OPTROM_IMAGES 4
+#define BX_N_SERIAL_PORTS 1
+#define BX_N_PARALLEL_PORTS 1
+#define BX_N_USB_HUBS 1
+
+typedef struct BOCHSAPI {
+  bx_floppy_options floppya;
+  bx_floppy_options floppyb;
+  bx_ata_options    ata[BX_MAX_ATA_CHANNEL];
+  bx_atadevice_options  atadevice[BX_MAX_ATA_CHANNEL][2];
+  // bx_disk_options   diskc;
+  // bx_disk_options   diskd;
+  // bx_cdrom_options  cdromd; 
+  bx_serial_options com[BX_N_SERIAL_PORTS];
+  bx_usb_options    usb[BX_N_USB_HUBS];
+  bx_rom_options    rom;
+  bx_vgarom_options vgarom;
+  bx_rom_options    optrom[BX_N_OPTROM_IMAGES]; // Optional rom images 
+  bx_mem_options    memory;
+  bx_parport_options par[BX_N_PARALLEL_PORTS]; // parallel ports
+  bx_sb16_options   sb16;
+  bx_param_num_c    *Obootdrive;  
+  bx_param_bool_c   *OfloppySigCheck;
+  bx_param_num_c    *Ovga_update_interval;
+  bx_param_num_c    *Okeyboard_serial_delay;
+  bx_param_num_c    *Okeyboard_paste_delay;
+  bx_param_enum_c   *Okeyboard_type;
+  bx_param_num_c    *Ofloppy_command_delay;
+  bx_param_num_c    *Oips;
+  bx_param_bool_c   *Orealtime_pit;
+  bx_param_bool_c   *Otext_snapshot_check;
+  bx_param_bool_c   *Omouse_enabled;
+  bx_param_bool_c   *Oprivate_colormap;
+#if BX_WITH_AMIGAOS
+  bx_param_bool_c   *Ofullscreen;
+  bx_param_string_c *Oscreenmode;
+#endif
+  bx_param_bool_c   *Oi440FXSupport;
+  bx_cmos_options   cmos;
+  bx_clock_options  clock;
+  bx_ne2k_options   ne2k;
+  bx_param_bool_c   *OnewHardDriveSupport;
+  bx_load32bitOSImage_t load32bitOSImage;
+  bx_log_options    log;
+  bx_keyboard_options keyboard;
+  bx_param_string_c *Ouser_shortcut;
+  bx_gdbstub_t      gdbstub;
+  bx_param_enum_c *Osel_config;
+  bx_param_enum_c *Osel_displaylib;
+  } bx_options_t;
+
+BOCHSAPI extern bx_options_t bx_options;
+
+void bx_center_print (FILE *file, char *line, int maxwidth);
+
+#if BX_PROVIDE_CPU_MEMORY==1
+#else
+// #  include "external_interface.h"
+#endif
+
+#define BX_USE_PS2_MOUSE 1
+
+int bx_init_hardware ();
+
+#include "instrument.h"
+
+// These are some convenience macros which abstract out accesses between
+// a variable in native byte ordering to/from guest (x86) memory, which is
+// always in little endian format.  You must deal with alignment (if your
+// system cares) and endian rearranging.  Don't assume anything.  You could
+// put some platform specific asm() statements here, to make use of native
+// instructions to help perform these operations more efficiently than C++.
+
+
+#ifdef __i386__
+
+#define WriteHostWordToLittleEndian(hostPtr,  nativeVar16) \
+    *((Bit16u*)(hostPtr)) = (nativeVar16)
+#define WriteHostDWordToLittleEndian(hostPtr, nativeVar32) \
+    *((Bit32u*)(hostPtr)) = (nativeVar32)
+#define WriteHostQWordToLittleEndian(hostPtr, nativeVar64) \
+    *((Bit64u*)(hostPtr)) = (nativeVar64)
+#define ReadHostWordFromLittleEndian(hostPtr, nativeVar16) \
+    (nativeVar16) = *((Bit16u*)(hostPtr))
+#define ReadHostDWordFromLittleEndian(hostPtr, nativeVar32) \
+    (nativeVar32) = *((Bit32u*)(hostPtr))
+#define ReadHostQWordFromLittleEndian(hostPtr, nativeVar64) \
+    (nativeVar64) = *((Bit64u*)(hostPtr))
+
+#else
+
+#define WriteHostWordToLittleEndian(hostPtr,  nativeVar16) { \
+    ((Bit8u *)(hostPtr))[0] = (Bit8u)  (nativeVar16); \
+    ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar16)>>8); \
+    }
+#define WriteHostDWordToLittleEndian(hostPtr, nativeVar32) { \
+    ((Bit8u *)(hostPtr))[0] = (Bit8u)  (nativeVar32); \
+    ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar32)>>8); \
+    ((Bit8u *)(hostPtr))[2] = (Bit8u) ((nativeVar32)>>16); \
+    ((Bit8u *)(hostPtr))[3] = (Bit8u) ((nativeVar32)>>24); \
+    }
+#define WriteHostQWordToLittleEndian(hostPtr, nativeVar64) { \
+    ((Bit8u *)(hostPtr))[0] = (Bit8u)  (nativeVar64); \
+    ((Bit8u *)(hostPtr))[1] = (Bit8u) ((nativeVar64)>>8); \
+    ((Bit8u *)(hostPtr))[2] = (Bit8u) ((nativeVar64)>>16); \
+    ((Bit8u *)(hostPtr))[3] = (Bit8u) ((nativeVar64)>>24); \
+    ((Bit8u *)(hostPtr))[4] = (Bit8u) ((nativeVar64)>>32); \
+    ((Bit8u *)(hostPtr))[5] = (Bit8u) ((nativeVar64)>>40); \
+    ((Bit8u *)(hostPtr))[6] = (Bit8u) ((nativeVar64)>>48); \
+    ((Bit8u *)(hostPtr))[7] = (Bit8u) ((nativeVar64)>>56); \
+    }
+#define ReadHostWordFromLittleEndian(hostPtr, nativeVar16) { \
+    (nativeVar16) =  ((Bit16u) ((Bit8u *)(hostPtr))[0]) | \
+                    (((Bit16u) ((Bit8u *)(hostPtr))[1])<<8) ; \
+    }
+#define ReadHostDWordFromLittleEndian(hostPtr, nativeVar32) { \
+    (nativeVar32) =  ((Bit32u) ((Bit8u *)(hostPtr))[0]) | \
+                    (((Bit32u) ((Bit8u *)(hostPtr))[1])<<8) | \
+                    (((Bit32u) ((Bit8u *)(hostPtr))[2])<<16) | \
+                    (((Bit32u) ((Bit8u *)(hostPtr))[3])<<24); \
+    }
+#define ReadHostQWordFromLittleEndian(hostPtr, nativeVar64) { \
+    (nativeVar64) =  ((Bit64u) ((Bit8u *)(hostPtr))[0]) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[1])<<8) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[2])<<16) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[3])<<24) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[4])<<32) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[5])<<40) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[6])<<48) | \
+                    (((Bit64u) ((Bit8u *)(hostPtr))[7])<<56); \
+    }
+
+#endif
+
+#ifdef BX_USE_VMX
+extern int domid;
+extern unsigned long megabytes;
+#endif
+
+#endif  /* BX_BOCHS_H */
diff --git a/tools/ioemu/include/bxversion.h b/tools/ioemu/include/bxversion.h
new file mode 100644 (file)
index 0000000..1c640f9
--- /dev/null
@@ -0,0 +1,7 @@
+/////////////////////////////////////////////////////////////////////////
+// This file is checked in as bxversion.h.in.  The configure script
+// substitutes variables and creates bxversion.h.
+/////////////////////////////////////////////////////////////////////////
+
+#define VER_STRING "2.1.1"
+#define REL_STRING "February 08, 2004"
diff --git a/tools/ioemu/include/config.h b/tools/ioemu/include/config.h
new file mode 100644 (file)
index 0000000..8d50f81
--- /dev/null
@@ -0,0 +1,919 @@
+/* config.h.  Generated by configure.  */
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// config.h.in is distributed in the source TAR file.  When you run
+// the configure script, it generates config.h with some changes
+// according to your build environment.  For example, in config.h.in,
+// SIZEOF_UNSIGNED_CHAR is set to 0.  When configure produces config.h
+// it will change "0" to the detected value for your system.
+//
+// config.h contains ONLY preprocessor #defines and a few typedefs.
+// It must be included by both C and C++ files, so it must not
+// contain anything language dependent such as a class declaration.
+//
+
+#ifdef _BX_CONFIG_H_
+#else
+#define _BX_CONFIG_H_ 1
+
+///////////////////////////////////////////////////////////////////
+// USER CONFIGURABLE OPTIONS : EDIT ONLY OPTIONS IN THIS SECTION //
+///////////////////////////////////////////////////////////////////
+
+
+#if 1
+// quit_sim is defined in gui/siminterface.h
+#define BX_EXIT(x)  SIM->quit_sim (x)
+#else
+// provide the real main and the usual exit.
+#define BX_EXIT(x)  ::exit(x)
+#endif
+
+#define BX_USE_CONFIG_INTERFACE 0
+#define BX_USE_VMX 1
+
+// I have tested the following combinations:
+//  * processors=1, bootstrap=0, ioapic_id=1   (uniprocessor system)
+//  * processors=2, bootstrap=0, ioapic_id=2
+//  * processors=4, bootstrap=2, ioapic_id=4
+#define BX_SMP_PROCESSORS 1
+#define BX_BOOTSTRAP_PROCESSOR 0
+// choose IOAPIC id to be equal to the number of processors.  This leaves
+// one space for each processor to have an ID, starting with 0.
+#define BX_IOAPIC_DEFAULT_ID 1
+
+#define BX_ADDRESS_SPACES 1
+// controls how many instances of BX_MEM_C are created.  For
+// SMP, use several processors with one shared memory space.
+// For cosimulation, you could use two processors and two address
+// spaces.
+
+#define BX_SUPPORT_APIC 0
+// include in APIC models, required for a multiprocessor system.
+
+#if (BX_SMP_PROCESSORS>1 && !BX_SUPPORT_APIC)
+#error For multiprocessor simulation, BX_SUPPORT_APIC is required.
+#endif
+
+#define BX_DEBUG_LINUX 0
+// if simulating Linux, this provides a few more debugging options
+// such as tracing all system calls.
+
+#define HAVE_LIBREADLINE 0
+#define HAVE_READLINE_HISTORY_H 1
+// adds support for the GNU readline library in the debugger command
+// prompt.
+
+#define HAVE_LOCALE_H 0
+// Define to 1 if you have <locale.h>
+
+// I rebuilt the code which provides timers to IO devices.
+// Setting this to 1 will introduce a little code which
+// will panic out if cases which shouldn't happen occur.
+// Set this to 0 for optimal performance.
+#define BX_TIMER_DEBUG 1
+
+// Settable A20 line.  For efficiency, you can disable
+// having a settable A20 line, eliminating conditional
+// code for every physical memory access.  You'll have
+// to tell your software not to mess with the A20 line,
+// and accept it as always being on if you change this.
+//   1 = use settable A20 line. (normal)
+//   0 = A20 is like the rest of the address lines
+
+#define BX_SUPPORT_A20 1
+
+// Processor Instructions Per Second
+// To find out what value to use for the 'ips' directive
+// in your '.bochsrc' file, set BX_SHOW_IPS to 1, and
+// run the software in bochs you plan to use most.  Bochs
+// will print out periodic IPS ratings.  This will change
+// based on the processor mode at the time, and various
+// other factors.  You'll get a reasonable estimate though.
+// When you're done, reset BX_SHOW_IPS to 0, do a
+// 'make all-clean', then 'make' again.
+
+#define BX_SHOW_IPS         0
+
+
+#if (BX_SHOW_IPS) && defined(__MINGW32__)
+#define        SIGALRM         14
+#endif
+
+// Paging Options:
+// ---------------
+// Support Paging mechanism.
+//   0 = don't support paging at all (DOS & Minix don't require it)
+//   1 = support paging.  (Most other OS's require paging)
+// Use Translation Lookaside Buffer (TLB) for caching
+// paging translations.  This will make paging mode
+// more efficient.  If you're OS doesn't use paging,
+// then you won't need either.
+//   1 = Use a TLB for effiency
+//   0 = don't use a TLB, walk the page tables for every access
+// BX_TLB_SIZE: Number of entries in TLB
+// BX_TLB_INDEX_OF(lpf): This macro is passed the linear page frame
+//   (top 20 bits of the linear address.  It must map these bits to
+//   one of the TLB cache slots, given the size of BX_TLB_SIZE.
+//   There will be a many-to-one mapping to each TLB cache slot.
+//   When there are collisions, the old entry is overwritten with
+//   one for the newest access.
+
+#define BX_SUPPORT_PAGING     1
+#define BX_USE_TLB 1
+
+#define BX_TLB_SIZE 1024
+#define BX_TLB_INDEX_OF(lpf) (((lpf) & 0x003ff000) >> 12)
+
+#define BX_USE_QUICK_TLB_INVALIDATE 0
+
+// Compile in support for DMA & FLOPPY IO.  You'll need this
+// if you plan to use the floppy drive emulation.  But if
+// you're environment doesn't require it, you can change
+// it to 0.
+
+#define BX_DMA_FLOPPY_IO 1
+
+
+// Default number of Megs of memory to emulate.  The
+// 'megs:' directive in the '.bochsrc' file overrides this,
+// allowing per-run settings.
+
+#define BX_DEFAULT_MEM_MEGS 4
+
+
+// CPU level emulation.  Default level is set in
+// the configure script.  BX_CPU_LEVEL defines the CPU level
+// to emulate.  BX_CPU_LEVEL_HACKED is a hack to define the
+// level of some integer instructions, so they can be tested
+// before the rest of the emulation is up to that level.
+
+#define BX_CPU_LEVEL 5
+#define BX_CPU_LEVEL_HACKED 5
+
+// emulate x86-64 instruction set?
+#define BX_SUPPORT_X86_64 0
+
+// Virtual 8086 mode emulation.
+//   1 = compile in support for v8086 mode.
+//   0 = don't compile in support for v8086 mode.
+#define BX_SUPPORT_V8086_MODE 1
+
+// Defines if the simulation should reset on triple fault
+// if set to 0, the simulation will panic.
+#define BX_RESET_ON_TRIPLE_FAULT 1
+
+// Support shadowing of ROM from C0000 to FFFFF.
+// This allows that region to be written to.
+#define BX_SHADOW_RAM 0
+
+// Number of CMOS registers
+#define BX_NUM_CMOS_REGS 64
+//#define BX_NUM_CMOS_REGS 128
+
+// Use Greg Alexander's new PIT model (summer 2001) instead of the original.
+#define BX_USE_NEW_PIT 1
+
+#define BX_USE_SLOWDOWN_TIMER 0
+#define BX_HAVE_SLEEP 1
+#define BX_HAVE_MSLEEP 0
+#define BX_HAVE_USLEEP 1
+#define BX_HAVE_NANOSLEEP 1
+#define BX_HAVE_ABORT 1
+#define BX_HAVE_SOCKLEN_T 1
+#define BX_HAVE_SOCKADDR_IN_SIN_LEN 0
+#define BX_HAVE_GETTIMEOFDAY 1
+#if defined(WIN32)
+#define BX_HAVE_REALTIME_USEC 1
+#else
+#define BX_HAVE_REALTIME_USEC (BX_HAVE_GETTIMEOFDAY)
+#endif
+#define BX_HAVE_MKSTEMP 1
+#define BX_HAVE_SYS_MMAN_H 1
+#define BX_HAVE_XPM_H 1
+#define BX_HAVE_TIMELOCAL 1
+#define BX_HAVE_GMTIME 1
+#define BX_HAVE_MKTIME 1
+
+// This turns on Roland Mainz's idle hack.  Presently it is specific to the X11
+// gui. If people try to enable it elsewhere, give a compile error after the
+// gui definition so that they don't waste their time trying.
+#define BX_USE_IDLE_HACK 0
+
+// Minimum Emulated IPS.
+// This is used in the realtime PIT as well as for checking the
+// IPS value set in the config file.
+#define BX_MIN_IPS 200000
+
+// Use Static Member Funtions to eliminate 'this' pointer passing
+// If you want the efficiency of 'C', you can make all the
+// members of the C++ CPU class to be static.
+// This defaults to 1 since it should improve performance, but when
+// SMP mode is enabled, it will be turned off by configure.
+
+#define BX_USE_CPU_SMF 1
+
+// Use static member functions in IO DEVice emulation modules.
+// For efficiency, use C like functions for IO handling,
+// and declare a device instance at compile time,
+// instead of using 'new' and storing the pointer.  This
+// eliminates some overhead, especially for high-use IO
+// devices like the disk drive.
+//   1 = Use static member efficiency (normal)
+//   0 = Use nonstatic member functions (use only if you need
+//       multiple instances of a device class
+
+#define BX_USE_HD_SMF      1  // Hard drive
+#define BX_USE_BIOS_SMF    1  // BIOS
+#define BX_USE_CMOS_SMF    1  // CMOS
+#define BX_USE_DMA_SMF     1  // DMA
+#define BX_USE_FD_SMF      1  // Floppy
+#define BX_USE_KEY_SMF     1  // Keyboard
+#define BX_USE_PAR_SMF     1  // Parallel
+#define BX_USE_PIC_SMF     1  // PIC
+#define BX_USE_PIT_SMF     1  // PIT
+#define BX_USE_SER_SMF     1  // Serial
+#define BX_USE_UM_SMF      1  // Unmapped
+#define BX_USE_VGA_SMF     1  // VGA
+#define BX_USE_SB16_SMF    1  // Sound (SB 16)
+#define BX_USE_DEV_SMF     1  // System Devices (port92)
+#define BX_USE_PCI_SMF     1  // PCI
+#define BX_USE_P2I_SMF     1  // PCI-to-ISA bridge
+#define BX_USE_PCIVGA_SMF  1  // PCI-VGA
+#define BX_USE_PCIUSB_SMF  1  // USB hub
+#define BX_USE_NE2K_SMF    1  // NE2K
+#define BX_USE_EFI_SMF     1  // External FPU IRQ
+#define BX_USE_GAME_SMF    1  // Gameport
+
+#define BX_PLUGINS 0
+#define BX_HAVE_DLFCN_H 1
+
+#if BX_PLUGINS && \
+  (   !BX_USE_HD_SMF || !BX_USE_BIOS_SMF || !BX_USE_CMOS_SMF \
+   || !BX_USE_DMA_SMF || !BX_USE_FD_SMF || !BX_USE_KEY_SMF \
+   || !BX_USE_PAR_SMF || !BX_USE_PIC_SMF || !BX_USE_PIT_SMF \
+   || !BX_USE_SER_SMF || !BX_USE_UM_SMF || !BX_USE_VGA_SMF \
+   || !BX_USE_SB16_SMF || !BX_USE_DEV_SMF || !BX_USE_PCI_SMF \
+   || !BX_USE_P2I_SMF || !BX_USE_PCIVGA_SMF || !BX_USE_PCIUSB_SMF \
+   || !BX_USE_NE2K_SMF || !BX_USE_EFI_SMF || !BX_USE_GAME_SMF)
+#error You must use SMF to have plugins
+#endif
+
+#define BX_SUPPORT_SB16 0
+#define BX_SUPPORT_GAME 0
+
+#if BX_SUPPORT_SB16
+// Use virtual methods for the sound output functions
+#define BX_USE_SOUND_VIRTUAL  1
+// Determines which sound output class is to be used.
+// Currently the following are available:
+//    bx_sound_linux_c      Output for Linux, to /dev/dsp and /dev/midi00
+//    bx_sound_windows_c    Output for Windows midi and wave mappers
+//    bx_sound_output_c     Dummy functions, no output
+#define BX_SOUND_OUTPUT_C  bx_sound_output_c
+#endif
+
+#define USE_RAW_SERIAL 0
+
+#define BX_USE_SPECIFIED_TIME0 0
+
+// This enables writing to port 0xe9 and the output
+// is sent to the console.  Reading from port 0xe9
+// will return 0xe9 to let you know this is available.
+// Leave this 0 unless you have a reason to use it.
+#define BX_PORT_E9_HACK 1
+
+#define BX_GDBSTUB 0
+
+// This option enables compressed (zlib) hd support
+#define BX_COMPRESSED_HD_SUPPORT 0
+#define BX_HAVE_ZLIB 1
+
+#if BX_COMPRESSED_HD_SUPPORT && !BX_HAVE_ZLIB
+#error You must have zlib to enable compressed hd support
+#endif
+
+// This option defines the number of supported ATA channels.
+// There are up to two drives per ATA channel.
+#define BX_MAX_ATA_CHANNEL 4
+
+#if (BX_MAX_ATA_CHANNEL>4 || BX_MAX_ATA_CHANNEL<1)
+#  error "BX_MAX_ATA_CHANNEL should be between 1 and 4"
+#endif
+
+// =================================================================
+// BEGIN: OPTIONAL DEBUGGER SECTION
+//
+// These options are only used if you compile in support for the
+// native command line debugging environment.  Typically, the debugger
+// is not used, and this section can be ignored.
+// =================================================================
+
+#define BX_MAX_DIRTY_PAGE_TABLE_MEGS 1024
+
+// Compile in support for virtual/linear/physical breakpoints.
+// Set to 1, only those you need.  Recommend using only linear
+// breakpoints, unless you need others.  Less supported means
+// slightly faster execution time.
+#define BX_DBG_SUPPORT_VIR_BPOINT 1
+#define BX_DBG_SUPPORT_LIN_BPOINT 1
+#define BX_DBG_SUPPORT_PHY_BPOINT 1
+
+// You need only define one initial breakpoint into each
+// cpu simulator (emulator) here.  Each simulator sets callbacks
+// and variables which the debugger uses from then on.
+#define BX_SIM1_INIT bx_dbg_init_cpu_mem_env0
+#ifndef BX_SIM2_INIT
+#define BX_SIM2_INIT bx_dbg_init_cpu_mem_env1
+#endif
+//#define BX_SIM2_INIT sim2_init
+
+// max number of virtual/linear/physical breakpoints handled
+#define BX_DBG_MAX_VIR_BPOINTS 10
+#define BX_DBG_MAX_LIN_BPOINTS 10
+#define BX_DBG_MAX_PHY_BPOINTS 10
+
+// max file pathname size for debugger commands
+#define BX_MAX_PATH     256
+// max nesting level for debug scripts including other scripts
+#define BX_INFILE_DEPTH  10
+// use this command to include (nest) debug scripts
+#define BX_INCLUDE_CMD   "source"
+
+// Use either 32 or 64 bit instruction counter for
+// debugger purposes.  Uncomment one of these.
+//#define BX_DBG_ICOUNT_SIZE   32
+#define BX_DBG_ICOUNT_SIZE   64
+
+// Make a call to command line debugger extensions.  If set to 1,
+// a call is made.  An external routine has a chance to process
+// the command.  If it does, than the debugger ignores the command.
+#define BX_DBG_EXTENSIONS 0
+
+// =================================================================
+// END: OPTIONAL DEBUGGER SECTION
+// =================================================================
+
+
+//////////////////////////////////////////////////////////////////////
+// END OF USER CONFIGURABLE OPTIONS : DON'T EDIT ANYTHING BELOW !!! //
+// THIS IS GENERATED BY THE ./configure SCRIPT                      //
+//////////////////////////////////////////////////////////////////////
+
+
+#define BX_WITH_X11 1
+#define BX_WITH_BEOS 0
+#define BX_WITH_WIN32 0
+#define BX_WITH_MACOS 0
+#define BX_WITH_CARBON 0
+#define BX_WITH_NOGUI 0
+#define BX_WITH_TERM 0
+#define BX_WITH_RFB 0
+#define BX_WITH_AMIGAOS 0
+#define BX_WITH_SDL 0
+#define BX_WITH_SVGA 0
+#define BX_WITH_WX 0
+
+// add special export symbols for win32 DLL building.  The main code must
+// have __declspec(dllexport) on variables, functions, or classes that the
+// plugins can access.  The plugins should #define PLUGGABLE which will
+// activate the __declspec(dllimport) instead.
+#if defined(WIN32) || defined(__CYGWIN__)
+#  if BX_PLUGINS && defined(BX_PLUGGABLE)
+//   #warning I will import DLL symbols from Bochs main program.
+#    define BOCHSAPI __declspec(dllimport)
+#  else
+//   #warning I will export DLL symbols.
+#    define BOCHSAPI __declspec(dllexport)
+#  endif
+#endif
+#ifndef BOCHSAPI
+#  define BOCHSAPI
+#endif
+
+#if defined(__CYGWIN__)
+// Make BOCHSAPI_CYGONLY exactly the same as BOCHSAPI.  This symbol
+// will be used for any cases where Cygwin requires a special tag
+// but VC++ does not.
+#define BOCHSAPI_CYGONLY BOCHSAPI
+#else
+// define the symbol to be empty
+#define BOCHSAPI_CYGONLY /*empty*/
+#endif
+
+#define BX_DEFAULT_CONFIG_INTERFACE "defined_by_configure"
+#define BX_DEFAULT_DISPLAY_LIBRARY "defined_by_configure"
+
+// Roland Mainz's idle hack is presently specific to X11. If people try to
+// enable it elsewhere, give a compile error so that they don't waste their
+// time trying.
+#if (BX_USE_IDLE_HACK && !BX_WITH_X11)
+#  error IDLE_HACK will only work with the X11 gui. Correct configure args and retry.
+#endif
+
+#define WORDS_BIGENDIAN 0
+
+#define SIZEOF_UNSIGNED_CHAR 1
+#define SIZEOF_UNSIGNED_SHORT 2
+#define SIZEOF_UNSIGNED_INT 4
+#define SIZEOF_UNSIGNED_LONG 4
+#define SIZEOF_UNSIGNED_LONG_LONG 8
+#define SIZEOF_INT_P 4
+
+#define BX_64BIT_CONSTANTS_USE_LL 1
+#if BX_64BIT_CONSTANTS_USE_LL
+// doesn't work on Microsoft Visual C++, maybe others
+#define BX_CONST64(x)  (x##LL)
+#else
+#define BX_CONST64(x)  (x)
+#endif
+
+#if defined(WIN32)
+  typedef unsigned char      Bit8u;
+  typedef   signed char      Bit8s;
+  typedef unsigned short     Bit16u;
+  typedef   signed short     Bit16s;
+  typedef unsigned int       Bit32u;
+  typedef   signed int       Bit32s;
+#ifdef __MINGW32__
+  typedef unsigned long long Bit64u;
+  typedef   signed long long Bit64s;
+#include <sys/types.h>
+#else
+  typedef unsigned __int64   Bit64u;
+  typedef   signed __int64   Bit64s;
+#endif
+#elif BX_WITH_MACOS
+  typedef unsigned char      Bit8u;
+  typedef   signed char      Bit8s;
+  typedef unsigned short     Bit16u;
+  typedef   signed short     Bit16s;
+  typedef unsigned int       Bit32u;
+  typedef   signed int       Bit32s;
+  typedef unsigned long long Bit64u;
+  typedef   signed long long Bit64s;
+#else
+
+// Unix like platforms
+
+#if SIZEOF_UNSIGNED_CHAR != 1
+#  error "sizeof (unsigned char) != 1"
+#else
+  typedef unsigned char Bit8u;
+  typedef   signed char Bit8s;
+#endif
+
+#if SIZEOF_UNSIGNED_SHORT != 2
+#  error "sizeof (unsigned short) != 2"
+#else
+  typedef unsigned short Bit16u;
+  typedef   signed short Bit16s;
+#endif
+
+#if SIZEOF_UNSIGNED_INT == 4
+  typedef unsigned int Bit32u;
+  typedef   signed int Bit32s;
+#elif SIZEOF_UNSIGNED_LONG == 4
+  typedef unsigned long Bit32u;
+  typedef   signed long Bit32s;
+#else
+#  error "can't find sizeof(type) of 4 bytes!"
+#endif
+
+#if SIZEOF_UNSIGNED_LONG == 8
+  typedef unsigned long Bit64u;
+  typedef   signed long Bit64s;
+#elif SIZEOF_UNSIGNED_LONG_LONG == 8
+  typedef unsigned long long Bit64u;
+  typedef   signed long long Bit64s;
+#else
+#  error "can't find data type of 8 bytes"
+#endif
+
+#endif
+
+// now that Bit32u and Bit64u exist, defined bx_address
+#if BX_SUPPORT_X86_64
+typedef Bit64u bx_address;
+#else
+typedef Bit32u bx_address;
+#endif
+
+
+// technically, in an 8 bit signed the real minimum is -128, not -127.
+// But if you decide to negate -128 you tend to get -128 again, so it's
+// better not to use the absolute maximum in the signed range.
+#define BX_MAX_BIT64U ( (Bit64u) -1           )
+#define BX_MIN_BIT64U ( 0                     )
+#define BX_MAX_BIT64S ( ((Bit64u) -1) >> 1    )
+#define BX_MIN_BIT64S ( -(((Bit64u) -1) >> 1) )
+#define BX_MAX_BIT32U ( (Bit32u) -1           )
+#define BX_MIN_BIT32U ( 0                     )
+#define BX_MAX_BIT32S ( ((Bit32u) -1) >> 1    )
+#define BX_MIN_BIT32S ( -(((Bit32u) -1) >> 1) )
+#define BX_MAX_BIT16U ( (Bit16u) -1           )
+#define BX_MIN_BIT16U ( 0                     )
+#define BX_MAX_BIT16S ( ((Bit16u) -1) >> 1    )
+#define BX_MIN_BIT16S ( -(((Bit16u) -1) >> 1) )
+#define BX_MAX_BIT8U  ( (Bit8u) -1            )
+#define BX_MIN_BIT8U  ( 0                     )
+#define BX_MAX_BIT8S  ( ((Bit8u) -1) >> 1     )
+#define BX_MIN_BIT8S  ( -(((Bit8u) -1) >> 1)  )
+
+
+// create an unsigned integer type that is the same size as a pointer.
+// You can typecast a pointer to a bx_pr_equiv_t without losing any
+// bits (and without getting the compiler excited).  This is used in
+// the FPU emulation code, where pointers and integers are often
+// used interchangeably.
+#if SIZEOF_INT_P == 4
+  typedef Bit32u bx_ptr_equiv_t;
+#elif SIZEOF_INT_P == 8
+  typedef Bit64u bx_ptr_equiv_t;
+#else
+#  error "could not define bx_ptr_equiv_t to size of int*"
+#endif
+
+// Use a boolean type that will not conflict with the builtin type
+// on any system.
+typedef Bit32u bx_bool;
+
+#if BX_WITH_MACOS
+#  define bx_ptr_t char *
+#else
+#  define bx_ptr_t void *
+#endif
+
+#if defined(WIN32)
+#  define BX_LITTLE_ENDIAN
+#elif BX_WITH_MACOS
+#  define BX_BIG_ENDIAN
+#else
+#if WORDS_BIGENDIAN
+#  define BX_BIG_ENDIAN
+#else
+#  define BX_LITTLE_ENDIAN
+#endif
+#endif // defined(WIN32)
+
+
+#if BX_SUPPORT_X86_64
+#ifdef BX_LITTLE_ENDIAN
+typedef
+  struct {
+         Bit64u lo;
+         Bit64u hi;
+         } Bit128u;
+typedef
+  struct {
+         Bit64u lo;
+         Bit64s hi;
+         } Bit128s;
+#else   // must be Big Endian
+typedef
+  struct {
+         Bit64u hi;
+         Bit64u lo;
+         } Bit128u;
+typedef
+  struct {
+         Bit64s hi;
+         Bit64u lo;
+         } Bit128s;
+#endif
+#endif  // #if BX_SUPPORT_X86_64
+
+
+// for now only term.cc requires a GUI sighandler.
+#define BX_GUI_SIGHANDLER (BX_WITH_TERM)
+
+#define HAVE_SIGACTION 1
+
+// configure will change the definition of "inline" to the value
+// that the C compiler allows.  It tests the following keywords to
+// see if any is permitted: inline, __inline__, __inline.  If none
+// is permitted, it defines inline to be empty.
+#define inline inline
+
+// inline functions in headers that are compiled with C compiler
+// (e.g. fpu code) are declared with BX_C_INLINE macro.  Note that
+// the word "inline" itself may now be redefined by the above #define.
+// Many compilers are known to work with "static inline".  If the
+// compiler can put the function inline, it does so and never creates
+// a symbol for the function.  If optimization is off, or inline is
+// defined to be empty, the static keyword causes the function to create
+// a symbol that's visible only to that .c file.  Each .c file that
+// includes the header will produde another local version of the
+// BX_C_INLINE function (not ideal).  However without "static" you can
+// duplicate symbol problems which are even worse.
+#define BX_C_INLINE static inline
+
+// Use BX_CPP_INLINE for all C++ inline functions.  Note that the
+// word "inline" itself may now be redefined by the above #define.
+#define BX_CPP_INLINE inline
+
+#ifdef __GNUC__
+
+// Some helpful compiler hints for compilers that allow them; GCC for now.
+//
+// BX_CPP_AlignN(n):
+//   Align a construct on an n-byte boundary.
+//
+// BX_CPP_AttrPrintf(formatArg, firstArg):
+//   This function takes printf-like arguments, so the compiler can check
+//   the consistency of the format string and the matching arguments.
+//   'formatArg' is the parameter number (starting from 1) of the format
+//   string argument.  'firstArg' is the parameter number of the 1st argument
+//   to check against the string argument.  NOTE: For non-static member
+//   functions, the this-ptr is argument number 1 but is invisible on
+//   the function prototype declaration - but you still have to count it.
+//
+// BX_CPP_AttrNoReturn():
+//   This function never returns.  The compiler can optimize-out following
+//   code accordingly.
+
+#define BX_CPP_AlignN(n) __attribute__ ((aligned (n)))
+#define BX_CPP_AttrPrintf(formatArg, firstArg) \
+                          __attribute__ ((format (printf, formatArg, firstArg)))
+#define BX_CPP_AttrNoReturn() __attribute__ ((noreturn))
+
+#else
+
+#define BX_CPP_AlignN(n) /* Not supported. */
+#define BX_CPP_AttrPrintf(formatArg, firstArg)  /* Not supported. */
+#define BX_CPP_AttrNoReturn() /* Not supported. */
+
+#endif
+
+#define BX_DEBUGGER 0
+#define BX_DISASM 0
+
+#define BX_PROVIDE_CPU_MEMORY 1
+#define BX_PROVIDE_DEVICE_MODELS 1
+
+#define BX_SUPPORT_VBE 0
+
+#define BX_PROVIDE_MAIN       1
+
+#define BX_INSTRUMENTATION 0
+
+#define BX_USE_LOADER    0
+
+// for debugger, CPU simulator handle ID
+//   0 is the default, for using only one CPU simulator
+//   1 is for the 2nd CPU simulator
+#define BX_SIM_ID 0
+#define BX_NUM_SIMULATORS 1
+
+// limited i440FX PCI support
+#define BX_PCI_SUPPORT 0
+
+// Experimental VGA on PCI
+#define BX_PCI_VGA_SUPPORT 1
+
+// limited USB on PCI
+#define BX_PCI_USB_SUPPORT 0
+
+#if (BX_PCI_USB_SUPPORT && !BX_PCI_SUPPORT)
+#error To enable USB, you must also enable PCI
+#endif
+
+// Promise VLBIDE DC2300 Support
+#define BX_PDC20230C_VLBIDE_SUPPORT 0
+
+#define BX_SUPPORT_FPU 1
+#define BX_SUPPORT_MMX 1
+#define BX_SUPPORT_3DNOW 0
+#define BX_SUPPORT_SSE 0
+#define BX_SUPPORT_DAZ 0
+#define BX_SUPPORT_PNI 0
+#define BX_SUPPORT_SEP 0
+#define BX_SUPPORT_4MEG_PAGES 0
+
+#define BX_SupportGuest2HostTLB 0
+#define BX_SupportRepeatSpeedups 0
+#define BX_SupportGlobalPages 0
+#define BX_SupportPAE 0
+#define BX_SupportICache 0
+#define BX_SupportHostAsms 1
+
+
+// if 1, don't do gpf on MSRs that we don't implement
+#define BX_IGNORE_BAD_MSR 0
+
+// ========================================================
+// These are some very temporary hacks I made to the 64-bit
+// support to help Peter with debugging etc.  They will be removed
+// soon and there is no configure option for them (on purpose).
+// By default, they are not compiled in.
+
+// I set this to 1 to bail in instructions which may not be honoring
+// the 64-bit widths of RIP/RSP.  If I trip a panic, then I clean
+// the function up and remove the panic.  You don't have to use
+// these.
+#if 0
+#define BailBigRSP(s) \
+  if ( (RIP > 0xffffffff) || \
+       (RSP > 0xffffffff) ) \
+    BX_PANIC((s ": bailing due to big RSP value, mode==%u", \
+              BX_CPU_THIS_PTR cpu_mode))
+#else
+#define BailBigRSP(s)
+#endif
+// ========================================================
+
+
+#if (BX_SUPPORT_MMX && BX_CPU_LEVEL < 5)
+#error With CPU level < 5, you must disable MMX support.
+#endif
+
+#if (!BX_SUPPORT_FPU && BX_CPU_LEVEL >= 5)
+#error With CPU level >= 5, you must enable FPU support.
+#endif
+
+#if (BX_SUPPORT_MMX && !BX_SUPPORT_FPU)
+#error "MMX cannot be compiled without FPU support"
+#endif
+
+#if (BX_SUPPORT_3DNOW && !BX_SUPPORT_MMX)
+#error "3DNow! cannot be compiled without MMX support"
+#endif
+
+#if (BX_SUPPORT_SSE && !BX_SUPPORT_MMX)
+#error "SSE cannot be compiled without FPU+MMX support"
+#endif
+
+#if (BX_CPU_LEVEL<6 && BX_SUPPORT_SSE)
+#error SSE is only supported with CPU_LEVEL >= 6
+#endif
+
+#if (BX_SUPPORT_PNI && BX_SUPPORT_SSE <= 1)
+#error "PNI cannot be compiled without SSE/SSE2 support"
+#endif
+
+#if (BX_CPU_LEVEL<6 && BX_SUPPORT_SEP)
+#error SYSENTER/SYSEXIT only supported with CPU_LEVEL >= 6
+#endif
+
+#if BX_SUPPORT_X86_64
+// Sanity checks to ensure that you cannot accidently use conflicting options.
+
+#if BX_CPU_LEVEL < 5
+#error X86-64 requires cpu level 6 or greater
+#endif
+#if (BX_SUPPORT_SSE<2)
+#error X86-64 requires SSE2
+#endif
+#if !BX_SupportPAE
+#error X86-64 requires Physical Address Extensions (PAE)
+#endif
+#if !BX_SupportGlobalPages
+#error X86-64 requires Page Global Extension (PGE)
+#endif
+#if !BX_SUPPORT_4MEG_PAGES
+#error X86-64 requires Page Size Extension (PSE)
+#endif
+
+#if BX_SUPPORT_SEP
+#error SYSENTER/SYSEXIT not implemented for X86-64
+#endif
+
+#endif
+
+#define BX_HAVE_GETENV 1
+#define BX_HAVE_SETENV 1
+#define BX_HAVE_SELECT 1
+#define BX_HAVE_SNPRINTF 1
+#define BX_HAVE_STRTOULL 1
+#define BX_HAVE_STRTOUQ 1
+#define BX_HAVE_STRDUP 1
+#define BX_HAVE_STRREV 0
+#define BX_HAVE_STRUCT_TIMEVAL 1
+
+// used in term gui
+#define BX_HAVE_COLOR_SET 0
+#define BX_HAVE_MVHLINE 0
+#define BX_HAVE_MVVLINE 0
+
+
+// set if your compiler does not permit an empty struct
+#define BX_NO_EMPTY_STRUCTS 0
+
+// set if your compiler does not understand __attribute__ after a struct
+#define BX_NO_ATTRIBUTES 0
+#if BX_NO_ATTRIBUTES
+#define GCC_ATTRIBUTE(x) /* attribute not supported */
+#else
+#define GCC_ATTRIBUTE __attribute__
+#endif
+
+// set to use fast function calls
+#define BX_FAST_FUNC_CALL 0
+
+// On gcc2.95+ x86 only
+#if BX_FAST_FUNC_CALL && defined(__i386__) && defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
+#  define BX_CPP_AttrRegparmN(X) __attribute__((regparm(X)))
+#else
+#  define BX_CPP_AttrRegparmN(X) /* Not defined */
+#endif
+
+// set if your compiler does not allow label at the end of a {} block
+#define BX_NO_BLANK_LABELS 0
+
+// set if you do have <hash_map>, used in bx_debug/dbg_main.c
+#define BX_HAVE_HASH_MAP 0
+
+// set if you do have <hash_map.h>, used in bx_debug/dbg_main.c
+#define BX_HAVE_HASH_MAP_H 1
+
+// set if you do have <set>, used in bx_debug/dbg_main.c
+#define BX_HAVE_SET 1
+
+// set if you do have <set.h>, used in bx_debug/dbg_main.c
+#define BX_HAVE_SET_H 1
+
+// Support x86 hardware debugger registers and facilites.
+// These are the debug facilites offered by the x86 architecture,
+// not the optional built-in debugger.
+#define BX_X86_DEBUGGER 0
+
+#define BX_SUPPORT_CDROM 1
+
+#if BX_SUPPORT_CDROM
+   // This is the C++ class name to use if we are supporting
+   // low-level CDROM.
+#  define LOWLEVEL_CDROM cdrom_interface
+#endif
+
+// NE2K network emulation
+#define BX_NE2K_SUPPORT 0
+#define BX_ETH_NULL_LOGGING 1
+#define BX_ETH_FBSD_LOGGING 1
+
+// determine which NE2K packet mover modules will be enabled
+// (this was moved from iodev/eth.h)
+#define ETH_NULL  1
+#ifdef BX_USE_ETH_ARPBACK
+#  define ETH_ARPBACK 1
+#endif
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+#define ETH_FBSD  1
+#endif
+#if defined(linux)
+#define ETH_LINUX 1
+#endif
+#if defined(WIN32)
+#define ETH_WIN32 1
+#endif
+
+// this enables Ethertap packet mover; determined by configure script
+#define HAVE_ETHERTAP 0
+
+// this enables TUN/TAP packet mover; determined by configure script
+#define HAVE_TUNTAP 0
+
+
+// I/O Interface to debug
+#define BX_IODEBUG_SUPPORT 0
+
+// External Debugger
+#define BX_EXTERNAL_DEBUGGER 0
+#define BX_OVERRIDE_ASK 0
+
+#ifdef WIN32
+#define BX_FLOPPY0_NAME "Floppy Disk A:"
+#define BX_FLOPPY1_NAME "Floppy Disk B:"
+#else
+#define BX_FLOPPY0_NAME "Floppy Disk 0"
+#define BX_FLOPPY1_NAME "Floppy Disk 1"
+#endif
+
+// This is handy for certain performance testing purposes, but otherwise
+// totally useless.  If you define BX_SCHEDULED_DIE_TIME then it enables code
+// in bx_pit_c::periodic that will cause Bochs to exit() after a certain number
+// of instructions.
+//#define BX_SCHEDULED_DIE_TIME 1162230000   // end of redhat6.0 boot
+
+
+#endif  // _BX_CONFIG_H
diff --git a/tools/ioemu/include/cpu/cpu.h b/tools/ioemu/include/cpu/cpu.h
new file mode 100644 (file)
index 0000000..0627ee3
--- /dev/null
@@ -0,0 +1,116 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cpu.h,v 1.155 2003/12/30 22:12:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#ifndef BX_CPU_H
+#  define BX_CPU_H 1
+
+#include <setjmp.h>
+#ifdef BX_USE_VMX
+extern "C" {
+#include <io/ioreq.h>
+}
+#endif
+
+
+#if BX_SUPPORT_APIC
+#define BX_CPU_INTR             (BX_CPU_THIS_PTR INTR || BX_CPU_THIS_PTR local_apic.INTR)
+#else
+#define BX_CPU_INTR             BX_CPU_THIS_PTR INTR
+#endif
+
+class BX_CPU_C;
+class BX_MEM_C;
+
+#if BX_USE_CPU_SMF == 0
+// normal member functions.  This can ONLY be used within BX_CPU_C classes.
+// Anyone on the outside should use the BX_CPU macro (defined in bochs.h)
+// instead.
+#  define BX_CPU_THIS_PTR  this->
+#  define BX_CPU_THIS      this
+#  define BX_SMF
+#  define BX_CPU_C_PREFIX  BX_CPU_C::
+// with normal member functions, calling a member fn pointer looks like
+// object->*(fnptr)(arg, ...);
+// Since this is different from when SMF=1, encapsulate it in a macro.
+#  define BX_CPU_CALL_METHOD(func, args) \
+            (this->*((BxExecutePtr_t) (func))) args
+#  define BX_CPU_CALL_METHODR(func, args) \
+            (this->*((BxExecutePtr_tR) (func))) args
+#else
+// static member functions.  With SMF, there is only one CPU by definition.
+#  define BX_CPU_THIS_PTR  BX_CPU(0)->
+#  define BX_CPU_THIS      BX_CPU(0)
+#  define BX_SMF           static
+#  define BX_CPU_C_PREFIX
+#  define BX_CPU_CALL_METHOD(func, args) \
+            ((BxExecutePtr_t) (func)) args
+#  define BX_CPU_CALL_METHODR(func, args) \
+            ((BxExecutePtr_tR) (func)) args
+#endif
+
+#if BX_SMP_PROCESSORS==1
+// single processor simulation, so there's one of everything
+BOCHSAPI extern BX_CPU_C       bx_cpu;
+#else
+// multiprocessor simulation, we need an array of cpus and memories
+BOCHSAPI extern BX_CPU_C       *bx_cpu_array[BX_SMP_PROCESSORS];
+#endif
+
+class BOCHSAPI BX_CPU_C : public logfunctions {
+
+public: // for now...
+
+  volatile bx_bool async_event;
+  volatile bx_bool INTR;
+  volatile bx_bool kill_bochs_request;
+
+  // constructors & destructors...
+  BX_CPU_C();
+  ~BX_CPU_C(void);
+  void init (BX_MEM_C *addrspace);
+  void interrupt(Bit8u vector);
+
+  BX_SMF void pagingA20Changed(void);
+  BX_SMF void reset(unsigned source);
+  BX_SMF void set_INTR(bx_bool value);
+  BX_SMF void     atexit(void);
+
+  // now for some ancillary functions...
+  void cpu_loop(Bit32s max_instr_count);
+
+#ifdef BX_USE_VMX
+  ioreq_t*     __get_ioreq(void);
+  ioreq_t*     get_ioreq(void);
+  void                 dispatch_ioreq(ioreq_t *req);
+  void         handle_ioreq();
+  void         timer_handler();
+
+  int send_event;
+#endif
+};
+
+#endif  // #ifndef BX_CPU_H
diff --git a/tools/ioemu/include/extplugin.h b/tools/ioemu/include/extplugin.h
new file mode 100644 (file)
index 0000000..f3e43f7
--- /dev/null
@@ -0,0 +1,51 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extplugin.h,v 1.4 2002/12/12 15:28:37 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// extplugin.h
+//
+// This header file defines the types necessary to make a Bochs plugin,
+// but without mentioning all the details of Bochs internals (bochs.h).  
+// It is included by the configuration interfaces and possibly other 
+// things which are intentionally isolated from other parts of the program.
+//
+// The plugin_t struct comes from the plugin.h file from plex86.
+// Plex86 is Copyright (C) 1999-2000  The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef __EXTPLUGIN_H
+#define __EXTPLUGIN_H
+
+#if BX_PLUGINS
+#include "ltdl.h"
+#endif
+
+enum plugintype_t {
+  PLUGTYPE_NULL=100,
+  PLUGTYPE_CORE,
+  PLUGTYPE_OPTIONAL,
+  PLUGTYPE_USER
+};
+
+#define MAX_ARGC 10
+
+typedef struct _plugin_t
+{
+    plugintype_t type;
+    int  initialized;
+#if BX_PLUGINS
+    lt_dlhandle handle;
+#endif
+    int  argc;
+    char *name, *args, *argv[MAX_ARGC];
+    int  (*plugin_init)(struct _plugin_t *plugin, plugintype_t type, int argc, char *argv[]);
+    void (*plugin_fini)(void);
+
+    struct _plugin_t *next;
+} plugin_t;
+
+
+
+#endif /* __EXTPLUGIN_H */
+
diff --git a/tools/ioemu/include/instrument.h b/tools/ioemu/include/instrument.h
new file mode 100644 (file)
index 0000000..8d753ff
--- /dev/null
@@ -0,0 +1,256 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: instrument.h,v 1.14 2003/10/09 19:05:13 sshwarts Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// possible types passed to BX_INSTR_TLB_CNTRL()
+#define BX_INSTR_MOV_CR3      10
+#define BX_INSTR_INVLPG       11
+#define BX_INSTR_TASKSWITCH   12
+
+// possible types passed to BX_INSTR_CACHE_CNTRL()
+#define BX_INSTR_INVD         20
+#define BX_INSTR_WBINVD       21
+
+#define BX_INSTR_IS_CALL  10
+#define BX_INSTR_IS_RET   11
+#define BX_INSTR_IS_IRET  12
+#define BX_INSTR_IS_JMP   13
+#define BX_INSTR_IS_INT   14
+
+#define BX_INSTR_PREFETCH_NTA 00
+#define BX_INSTR_PREFETCH_T0  01
+#define BX_INSTR_PREFETCH_T1  02
+#define BX_INSTR_PREFETCH_T2  03
+
+
+
+
+
+#if BX_INSTRUMENTATION
+
+class bxInstruction_c;
+
+// called from the CPU core
+
+void bx_instr_init(unsigned cpu);
+void bx_instr_shutdown(unsigned cpu);
+void bx_instr_reset(unsigned cpu);
+void bx_instr_new_instruction(unsigned cpu);
+
+void bx_instr_debug_promt();
+void bx_instr_start();
+void bx_instr_stop();
+void bx_instr_print();
+
+void bx_instr_cnear_branch_taken(unsigned cpu, bx_address new_eip);
+void bx_instr_cnear_branch_not_taken(unsigned cpu);
+void bx_instr_ucnear_branch(unsigned cpu, unsigned what, bx_address new_eip);
+void bx_instr_far_branch(unsigned cpu, unsigned what, Bit16u new_cs, bx_address new_eip);
+
+void bx_instr_opcode(unsigned cpu, Bit8u *opcode, unsigned len, bx_bool is32);
+void bx_instr_fetch_decode_completed(unsigned cpu, const bxInstruction_c *i);
+
+void bx_instr_prefix_as(unsigned cpu);
+void bx_instr_prefix_os(unsigned cpu);
+void bx_instr_prefix_rep(unsigned cpu);
+void bx_instr_prefix_repne(unsigned cpu);
+void bx_instr_prefix_lock(unsigned cpu);
+void bx_instr_prefix_cs(unsigned cpu);
+void bx_instr_prefix_ss(unsigned cpu);
+void bx_instr_prefix_ds(unsigned cpu);
+void bx_instr_prefix_es(unsigned cpu);
+void bx_instr_prefix_fs(unsigned cpu);
+void bx_instr_prefix_gs(unsigned cpu);
+void bx_instr_prefix_extend8b(unsigned cpu);
+
+void bx_instr_interrupt(unsigned cpu, unsigned vector);
+void bx_instr_exception(unsigned cpu, unsigned vector);
+void bx_instr_hwinterrupt(unsigned cpu, unsigned vector, Bit16u cs, bx_address eip);
+
+void bx_instr_tlb_cntrl(unsigned cpu, unsigned what, Bit32u newval);
+void bx_instr_cache_cntrl(unsigned cpu, unsigned what);
+void bx_instr_prefetch_hint(unsigned cpu, unsigned what, unsigned seg, bx_address offset);
+
+void bx_instr_before_execution(unsigned cpu);
+void bx_instr_after_execution(unsigned cpu);
+void bx_instr_repeat_iteration(unsigned cpu);
+
+void bx_instr_inp(Bit16u addr, unsigned len);
+void bx_instr_outp(Bit16u addr, unsigned len);
+void bx_instr_inp2(Bit16u addr, unsigned len, unsigned val);
+void bx_instr_outp2(Bit16u addr, unsigned len, unsigned val);
+
+void bx_instr_mem_code(unsigned cpu, bx_address linear, unsigned size);
+void bx_instr_mem_data(unsigned cpu, bx_address linear, unsigned size, unsigned rw);
+
+void bx_instr_lin_read(unsigned cpu, bx_address lin, bx_address phy, unsigned len);
+void bx_instr_lin_write(unsigned cpu, bx_address lin, bx_address phy, unsigned len);
+
+void bx_instr_phy_write(unsigned cpu, bx_address addr, unsigned len);
+void bx_instr_phy_read(unsigned cpu, bx_address addr, unsigned len);
+
+/* simulation init, shutdown, reset */
+#  define BX_INSTR_INIT(cpu_id)            bx_instr_init(cpu_id)
+#  define BX_INSTR_SHUTDOWN(cpu_id)        bx_instr_shutdown(cpu_id)
+#  define BX_INSTR_RESET(cpu_id)           bx_instr_reset(cpu_id)
+#  define BX_INSTR_NEW_INSTRUCTION(cpu_id) bx_instr_new_instruction(cpu_id)
+
+/* called from command line debugger */
+#  define BX_INSTR_DEBUG_PROMPT()          bx_instr_debug_promt()
+#  define BX_INSTR_START()                 bx_instr_start()
+#  define BX_INSTR_STOP()                  bx_instr_stop()
+#  define BX_INSTR_PRINT()                 bx_instr_print()
+
+/* branch resoultion */
+#  define BX_INSTR_CNEAR_BRANCH_TAKEN(cpu_id, new_eip)       bx_instr_cnear_branch_taken(cpu_id, new_eip)
+#  define BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(cpu_id)   bx_instr_cnear_branch_not_taken(cpu_id)
+#  define BX_INSTR_UCNEAR_BRANCH(cpu_id, what, new_eip)      bx_instr_ucnear_branch(cpu_id, what, new_eip)
+#  define BX_INSTR_FAR_BRANCH(cpu_id, what, new_cs, new_eip) bx_instr_far_branch(cpu_id, what, new_cs, new_eip)
+
+/* decoding completed */
+#  define BX_INSTR_OPCODE(cpu_id, opcode, len, is32) \
+                       bx_instr_opcode(cpu_id, opcode, len, is32)
+#  define BX_INSTR_FETCH_DECODE_COMPLETED(cpu_id, i) \
+                       bx_instr_fetch_decode_completed(cpu_id, i)
+     
+/* prefix decoded */
+#  define BX_INSTR_PREFIX_AS(cpu_id)       bx_instr_prefix_as(cpu_id)
+#  define BX_INSTR_PREFIX_OS(cpu_id)       bx_instr_prefix_os(cpu_id)
+#  define BX_INSTR_PREFIX_REP(cpu_id)      bx_instr_prefix_rep(cpu_id)
+#  define BX_INSTR_PREFIX_REPNE(cpu_id)    bx_instr_prefix_repne(cpu_id)
+#  define BX_INSTR_PREFIX_LOCK(cpu_id)     bx_instr_prefix_lock(cpu_id)
+#  define BX_INSTR_PREFIX_CS(cpu_id)       bx_instr_prefix_cs(cpu_id)
+#  define BX_INSTR_PREFIX_SS(cpu_id)       bx_instr_prefix_ss(cpu_id)
+#  define BX_INSTR_PREFIX_DS(cpu_id)       bx_instr_prefix_ds(cpu_id)
+#  define BX_INSTR_PREFIX_ES(cpu_id)       bx_instr_prefix_es(cpu_id)
+#  define BX_INSTR_PREFIX_FS(cpu_id)       bx_instr_prefix_fs(cpu_id)
+#  define BX_INSTR_PREFIX_GS(cpu_id)       bx_instr_prefix_gs(cpu_id)
+#  define BX_INSTR_PREFIX_EXTEND8B(cpu_id) bx_instr_prefix_extend8b(cpu_id)
+
+/* exceptional case and interrupt */
+#  define BX_INSTR_EXCEPTION(cpu_id, vector)            bx_instr_exception(cpu_id, vector)
+#  define BX_INSTR_INTERRUPT(cpu_id, vector)            bx_instr_interrupt(cpu_id, vector)
+#  define BX_INSTR_HWINTERRUPT(cpu_id, vector, cs, eip) bx_instr_hwinterrupt(cpu_id, vector, cs, eip)
+
+/* TLB/CACHE control instruction executed */
+#  define BX_INSTR_CACHE_CNTRL(cpu_id, what)            bx_instr_cache_cntrl(cpu_id, what)
+#  define BX_INSTR_TLB_CNTRL(cpu_id, what, newval)      bx_instr_tlb_cntrl(cpu_id, what, newval)
+#  define BX_INSTR_PREFETCH_HINT(cpu_id, what, seg, offset) \
+                       bx_instr_prefetch_hint(cpu_id, what, seg, offset)
+
+/* execution */
+#  define BX_INSTR_BEFORE_EXECUTION(cpu_id)             bx_instr_before_execution(cpu_id)
+#  define BX_INSTR_AFTER_EXECUTION(cpu_id)              bx_instr_after_execution(cpu_id)
+#  define BX_INSTR_REPEAT_ITERATION(cpu_id)             bx_instr_repeat_iteration(cpu_id)
+
+/* memory access */
+#  define BX_INSTR_LIN_READ(cpu_id, lin, phy, len)      bx_instr_lin_read(cpu_id, lin, phy, len)
+#  define BX_INSTR_LIN_WRITE(cpu_id, lin, phy, len)     bx_instr_lin_write(cpu_id, lin, phy, len)
+
+#  define BX_INSTR_MEM_CODE(cpu_id, linear, size)       bx_instr_mem_code(cpu_id, linear, size)
+#  define BX_INSTR_MEM_DATA(cpu_id, linear, size, rw)   bx_instr_mem_data(cpu_id, linear, size, rw)
+
+/* called from memory object */
+#  define BX_INSTR_PHY_WRITE(cpu_id, addr, len)         bx_instr_phy_write(cpu_id, addr, len)
+#  define BX_INSTR_PHY_READ(cpu_id, addr, len)          bx_instr_phy_read(cpu_id, addr, len)
+
+/* feedback from device units */
+#  define BX_INSTR_INP(addr, len)               bx_instr_inp(addr, len)
+#  define BX_INSTR_INP2(addr, len, val)         bx_instr_inp2(addr, len, val)
+#  define BX_INSTR_OUTP(addr, len)              bx_instr_outp(addr, len)
+#  define BX_INSTR_OUTP2(addr, len, val)        bx_instr_outp2(addr, len, val)
+
+#else   
+
+/* simulation init, shutdown, reset */
+#  define BX_INSTR_INIT(cpu_id)
+#  define BX_INSTR_SHUTDOWN(cpu_id)
+#  define BX_INSTR_RESET(cpu_id)
+#  define BX_INSTR_NEW_INSTRUCTION(cpu_id)
+
+/* called from command line debugger */
+#  define BX_INSTR_DEBUG_PROMPT()
+#  define BX_INSTR_START()
+#  define BX_INSTR_STOP()
+#  define BX_INSTR_PRINT()
+
+/* branch resoultion */
+#  define BX_INSTR_CNEAR_BRANCH_TAKEN(cpu_id, new_eip)
+#  define BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(cpu_id)
+#  define BX_INSTR_UCNEAR_BRANCH(cpu_id, what, new_eip)
+#  define BX_INSTR_FAR_BRANCH(cpu_id, what, new_cs, new_eip)
+
+/* decoding completed */
+#  define BX_INSTR_OPCODE(cpu_id, opcode, len, is32) 
+#  define BX_INSTR_FETCH_DECODE_COMPLETED(cpu_id, i)
+     
+/* prefix decoded */
+#  define BX_INSTR_PREFIX_AS(cpu_id)
+#  define BX_INSTR_PREFIX_OS(cpu_id)
+#  define BX_INSTR_PREFIX_REP(cpu_id)
+#  define BX_INSTR_PREFIX_REPNE(cpu_id)
+#  define BX_INSTR_PREFIX_LOCK(cpu_id)
+#  define BX_INSTR_PREFIX_CS(cpu_id)
+#  define BX_INSTR_PREFIX_SS(cpu_id)
+#  define BX_INSTR_PREFIX_DS(cpu_id)
+#  define BX_INSTR_PREFIX_ES(cpu_id)
+#  define BX_INSTR_PREFIX_FS(cpu_id)
+#  define BX_INSTR_PREFIX_GS(cpu_id)
+#  define BX_INSTR_PREFIX_EXTEND8B(cpu_id)
+
+/* exceptional case and interrupt */
+#  define BX_INSTR_EXCEPTION(cpu_id, vector)
+#  define BX_INSTR_INTERRUPT(cpu_id, vector)
+#  define BX_INSTR_HWINTERRUPT(cpu_id, vector, cs, eip)
+
+/* TLB/CACHE control instruction executed */
+#  define BX_INSTR_CACHE_CNTRL(cpu_id, what)
+#  define BX_INSTR_TLB_CNTRL(cpu_id, what, newval)
+#  define BX_INSTR_PREFETCH_HINT(cpu_id, what, seg, offset)
+
+/* execution */
+#  define BX_INSTR_BEFORE_EXECUTION(cpu_id)
+#  define BX_INSTR_AFTER_EXECUTION(cpu_id)
+#  define BX_INSTR_REPEAT_ITERATION(cpu_id)
+
+/* memory access */
+#  define BX_INSTR_LIN_READ(cpu_id, lin, phy, len)
+#  define BX_INSTR_LIN_WRITE(cpu_id, lin, phy, len)
+
+#  define BX_INSTR_MEM_CODE(cpu_id, linear, size)      
+#  define BX_INSTR_MEM_DATA(cpu_id, linear, size, rw)
+
+/* called from memory object */
+#  define BX_INSTR_PHY_WRITE(cpu_id, addr, len)
+#  define BX_INSTR_PHY_READ(cpu_id, addr, len)
+
+/* feedback from device units */
+#  define BX_INSTR_INP(addr, len)
+#  define BX_INSTR_INP2(addr, len, val)
+#  define BX_INSTR_OUTP(addr, len)
+#  define BX_INSTR_OUTP2(addr, len, val)
+
+#endif  
diff --git a/tools/ioemu/include/ltdl.h b/tools/ioemu/include/ltdl.h
new file mode 100644 (file)
index 0000000..3a02b31
--- /dev/null
@@ -0,0 +1,398 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ltdl.h,v 1.2 2002/10/24 21:04:37 bdenney Exp $
+//
+// NOTE: The ltdl library comes from the Libtool package.  Bochs uses
+// ltdl and libtool to build and load plugins.  The libtool
+// documentation describes how to copy ltdl.c and ltdl.h into your
+// distribution, so it is clearly legal to do so.
+/////////////////////////////////////////////////////////////////////////
+
+/* ltdl.h -- generic dlopen functions
+   Copyright (C) 1998-2000 Free Software Foundation, Inc.
+   Originally by Thomas Tanner <tanner@ffii.org>
+   This file is part of GNU Libtool.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+As a special exception to the GNU Lesser General Public License,
+if you distribute this file as part of a program or library that
+is built using GNU libtool, you may include it under the same
+distribution terms that you use for the rest of that program.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307  USA
+*/
+
+/* Only include this header file once. */
+#ifndef LTDL_H
+#define LTDL_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <sys/types.h>         /* for size_t declaration */
+#ifdef __cplusplus
+};
+#endif
+
+\f
+/* --- MACROS FOR PORTABILITY --- */
+
+
+/* Saves on those hard to debug '\0' typos....  */
+#define LT_EOS_CHAR    '\0'
+
+/* LTDL_BEGIN_C_DECLS should be used at the beginning of your declarations,
+   so that C++ compilers don't mangle their names.  Use LTDL_END_C_DECLS at
+   the end of C declarations. */
+#ifdef __cplusplus
+# define LT_BEGIN_C_DECLS      extern "C" {
+# define LT_END_C_DECLS                }
+#else
+# define LT_BEGIN_C_DECLS      /* empty */
+# define LT_END_C_DECLS                /* empty */
+#endif
+
+LT_BEGIN_C_DECLS
+
+
+/* LT_PARAMS is a macro used to wrap function prototypes, so that compilers
+   that don't understand ANSI C prototypes still work, and ANSI C
+   compilers can issue warnings about type mismatches.  */
+#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(WIN32) || defined(__cplusplus)
+# define LT_PARAMS(protos)     protos
+# define lt_ptr                void*
+#else
+# define LT_PARAMS(protos)     ()
+# define lt_ptr                char*
+#endif
+
+/* LT_STMT_START/END are used to create macros which expand to a
+   a single compound statement in a portable way.  */
+#if defined (__GNUC__) && !defined (__STRICT_ANSI__) && !defined (__cplusplus)
+#  define LT_STMT_START        (void)(
+#  define LT_STMT_END          )
+#else
+#  if (defined (sun) || defined (__sun__))
+#    define LT_STMT_START      if (1)
+#    define LT_STMT_END        else (void)0
+#  else
+#    define LT_STMT_START      do
+#    define LT_STMT_END        while (0)
+#  endif
+#endif
+
+/* LT_CONC creates a new concatenated symbol for the compiler
+   in a portable way.  */
+#if defined(__STDC__) || defined(__cplusplus)
+#  define LT_CONC(s,t) s##t
+#else
+#  define LT_CONC(s,t) s/**/t
+#endif
+
+/* LT_STRLEN can be used safely on NULL pointers.  */
+#define LT_STRLEN(s)   (((s) && (s)[0]) ? strlen (s) : 0)
+
+
+\f
+/* --- WINDOWS SUPPORT --- */
+
+
+/* Canonicalise Windows and Cygwin recognition macros.  */
+#ifdef __CYGWIN32__
+#  ifndef __CYGWIN__
+#    define __CYGWIN__ __CYGWIN32__
+#  endif
+#endif
+#if defined(_WIN32) || defined(WIN32)
+#  ifndef __WINDOWS__
+#    ifdef _WIN32
+#      define __WINDOWS__ _WIN32
+#    else
+#      ifdef WIN32
+#        define __WINDOWS__ WIN32
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __WINDOWS__
+#  ifndef __CYGWIN__
+/* LT_DIRSEP_CHAR is accepted *in addition* to '/' as a directory
+   separator when it is set. */
+#    define LT_DIRSEP_CHAR     '\\'
+#    define LT_PATHSEP_CHAR    ';'
+#  endif
+#endif
+#ifndef LT_PATHSEP_CHAR
+#  define LT_PATHSEP_CHAR      ':'
+#endif
+
+/* DLL building support on win32 hosts;  mostly to workaround their
+   ridiculous implementation of data symbol exporting. */
+#ifndef LT_SCOPE
+#  ifdef __WINDOWS__
+#    ifdef DLL_EXPORT          /* defined by libtool (if required) */
+#      define LT_SCOPE __declspec(dllexport)
+#    endif
+#    ifdef LIBLTDL_DLL_IMPORT  /* define if linking with this dll */
+#      define LT_SCOPE extern __declspec(dllimport)
+#    endif
+#  endif
+#  ifndef LT_SCOPE             /* static linking or !__WINDOWS__ */
+#    define LT_SCOPE   extern
+#  endif
+#endif
+
+
+
+\f
+/* --- DYNAMIC MODULE LOADING API --- */
+
+
+typedef        struct lt_dlhandle_struct *lt_dlhandle; /* A loaded module.  */
+
+/* Initialisation and finalisation functions for libltdl. */
+extern int         lt_dlinit           LT_PARAMS((void));
+extern int         lt_dlexit           LT_PARAMS((void));
+
+/* Module search path manipulation.  */
+extern int         lt_dladdsearchdir    LT_PARAMS((const char *search_dir));
+extern int         lt_dlinsertsearchdir LT_PARAMS((const char *before,
+                                                   const char *search_dir));
+extern int         lt_dlsetsearchpath   LT_PARAMS((const char *search_path));
+extern const char *lt_dlgetsearchpath   LT_PARAMS((void));
+extern int         lt_dlforeachfile     LT_PARAMS((
+                       const char *search_path,
+                       int (*func) (const char *filename, lt_ptr data),
+                       lt_ptr data));
+
+/* Portable libltdl versions of the system dlopen() API. */
+extern lt_dlhandle lt_dlopen           LT_PARAMS((const char *filename));
+extern lt_dlhandle lt_dlopenext        LT_PARAMS((const char *filename));
+extern lt_ptr      lt_dlsym            LT_PARAMS((lt_dlhandle handle,
+                                                    const char *name));
+extern const char *lt_dlerror          LT_PARAMS((void));
+extern int         lt_dlclose          LT_PARAMS((lt_dlhandle handle));
+
+/* Module residency management. */
+extern int         lt_dlmakeresident   LT_PARAMS((lt_dlhandle handle));
+extern int         lt_dlisresident     LT_PARAMS((lt_dlhandle handle));
+
+
+
+\f
+/* --- MUTEX LOCKING --- */
+
+
+typedef void   lt_dlmutex_lock         LT_PARAMS((void));
+typedef void   lt_dlmutex_unlock       LT_PARAMS((void));
+typedef void   lt_dlmutex_seterror     LT_PARAMS((const char *errmsg));
+typedef const char *lt_dlmutex_geterror        LT_PARAMS((void));
+
+extern int     lt_dlmutex_register     LT_PARAMS((lt_dlmutex_lock *lock,
+                                           lt_dlmutex_unlock *unlock,
+                                           lt_dlmutex_seterror *seterror,
+                                           lt_dlmutex_geterror *geterror));
+
+
+
+\f
+/* --- MEMORY HANDLING --- */
+
+
+/* By default, the realloc function pointer is set to our internal
+   realloc implementation which iself uses lt_dlmalloc and lt_dlfree.
+   libltdl relies on a featureful realloc, but if you are sure yours
+   has the right semantics then you can assign it directly.  Generally,
+   it is safe to assign just a malloc() and a free() function.  */
+LT_SCOPE  lt_ptr   (*lt_dlmalloc)      LT_PARAMS((size_t size));
+LT_SCOPE  lt_ptr   (*lt_dlrealloc)     LT_PARAMS((lt_ptr ptr, size_t size));
+LT_SCOPE  void    (*lt_dlfree)         LT_PARAMS((lt_ptr ptr));
+
+
+
+\f
+/* --- PRELOADED MODULE SUPPORT --- */
+
+
+/* A preopened symbol. Arrays of this type comprise the exported
+   symbols for a dlpreopened module. */
+typedef struct {
+  const char *name;
+  lt_ptr      address;
+} lt_dlsymlist;
+
+extern int     lt_dlpreload    LT_PARAMS((const lt_dlsymlist *preloaded));
+extern int     lt_dlpreload_default
+                               LT_PARAMS((const lt_dlsymlist *preloaded));
+
+#define LTDL_SET_PRELOADED_SYMBOLS()           LT_STMT_START{  \
+       extern const lt_dlsymlist lt_preloaded_symbols[];               \
+       lt_dlpreload_default(lt_preloaded_symbols);                     \
+                                               }LT_STMT_END
+
+
+
+\f
+/* --- MODULE INFORMATION --- */
+
+
+/* Read only information pertaining to a loaded module. */
+typedef        struct {
+  char *filename;              /* file name */
+  char *name;                  /* module name */
+  int  ref_count;              /* number of times lt_dlopened minus
+                                  number of times lt_dlclosed. */
+} lt_dlinfo;
+
+extern const lt_dlinfo *lt_dlgetinfo       LT_PARAMS((lt_dlhandle handle));
+extern lt_dlhandle     lt_dlhandle_next    LT_PARAMS((lt_dlhandle place));
+extern int             lt_dlforeach        LT_PARAMS((
+                               int (*func) (lt_dlhandle handle, lt_ptr data),
+                               lt_ptr data));
+
+/* Associating user data with loaded modules. */
+typedef unsigned lt_dlcaller_id;
+
+extern lt_dlcaller_id  lt_dlcaller_register  LT_PARAMS((void));
+extern lt_ptr          lt_dlcaller_set_data  LT_PARAMS((lt_dlcaller_id key,
+                                               lt_dlhandle handle,
+                                               lt_ptr data));
+extern lt_ptr          lt_dlcaller_get_data  LT_PARAMS((lt_dlcaller_id key,
+                                               lt_dlhandle handle));
+
+
+\f
+/* --- USER MODULE LOADER API --- */
+
+
+typedef        struct lt_dlloader      lt_dlloader;
+typedef lt_ptr                 lt_user_data;
+typedef lt_ptr                 lt_module;
+
+/* Function pointer types for creating user defined module loaders. */
+typedef lt_module   lt_module_open     LT_PARAMS((lt_user_data loader_data,
+                                           const char *filename));
+typedef int        lt_module_close     LT_PARAMS((lt_user_data loader_data,
+                                           lt_module handle));
+typedef lt_ptr     lt_find_sym         LT_PARAMS((lt_user_data loader_data,
+                                           lt_module handle,
+                                           const char *symbol));
+typedef int        lt_dlloader_exit    LT_PARAMS((lt_user_data loader_data));
+
+struct lt_user_dlloader {
+  const char          *sym_prefix;
+  lt_module_open       *module_open;
+  lt_module_close      *module_close;
+  lt_find_sym         *find_sym;
+  lt_dlloader_exit     *dlloader_exit;
+  lt_user_data         dlloader_data;
+};
+
+extern lt_dlloader    *lt_dlloader_next    LT_PARAMS((lt_dlloader *place));
+extern lt_dlloader    *lt_dlloader_find    LT_PARAMS((
+                                               const char *loader_name));
+extern const char     *lt_dlloader_name    LT_PARAMS((lt_dlloader *place));
+extern lt_user_data   *lt_dlloader_data    LT_PARAMS((lt_dlloader *place));
+extern int             lt_dlloader_add     LT_PARAMS((lt_dlloader *place,
+                               const struct lt_user_dlloader *dlloader,
+                               const char *loader_name));
+extern int             lt_dlloader_remove  LT_PARAMS((
+                                               const char *loader_name));
+
+
+\f
+/* --- ERROR MESSAGE HANDLING --- */
+
+/* Bryce rewrote the error table in a way that would be likely to work
+   on all compilers.  VC++ was not able to handle it the way it was
+   done originally. */
+
+/* ORIG COMMENT: Defining error strings alongside their symbolic names in a
+   macro in this way allows us to expand the macro in different contexts with
+   confidence that the enumeration of symbolic names will map correctly
+   onto the table of error strings.  */
+
+#define lt_dlerror_symbols_list                                                \
+  LT_ERROR_UNKNOWN,                                                    \
+  LT_ERROR_DLOPEN_NOT_SUPPORTED,                                       \
+  LT_ERROR_INVALID_LOADER,                                             \
+  LT_ERROR_INIT_LOADER,                                                        \
+  LT_ERROR_REMOVE_LOADER,                                              \
+  LT_ERROR_FILE_NOT_FOUND,                                             \
+  LT_ERROR_DEPLIB_NOT_FOUND,                                           \
+  LT_ERROR_NO_SYMBOLS,                                                 \
+  LT_ERROR_CANNOT_OPEN,                                                        \
+  LT_ERROR_CANNOT_CLOSE,                                               \
+  LT_ERROR_SYMBOL_NOT_FOUND,                                           \
+  LT_ERROR_NO_MEMORY,                                                  \
+  LT_ERROR_INVALID_HANDLE,                                             \
+  LT_ERROR_BUFFER_OVERFLOW,                                            \
+  LT_ERROR_INVALID_ERRORCODE,                                          \
+  LT_ERROR_SHUTDOWN,                                                   \
+  LT_ERROR_CLOSE_RESIDENT_MODULE,                                      \
+  LT_ERROR_INVALID_MUTEX_ARGS,                                         \
+  LT_ERROR_INVALID_POSITION,
+
+#define lt_dlerror_names_list                                          \
+    "unknown error",                                                   \
+    "dlopen support not available",                                    \
+    "invalid loader",                                                  \
+    "loader initialization failed",                                    \
+    "loader removal failed",                                           \
+    "file not found",                                                  \
+    "dependency library not found",                                    \
+    "no symbols defined",                                              \
+    "can't open the module",                                           \
+    "can't close the module",                                          \
+    "symbol not found",                                                        \
+    "not enough memory",                                               \
+    "invalid module handle",                                           \
+    "internal buffer overflow",                                                \
+    "invalid errorcode",                                               \
+    "library already shutdown",                                                \
+    "can't close resident module",                                     \
+    "invalid mutex handler registration",                              \
+    "invalid search path insert position",
+
+/* Enumerate the symbolic error names. */
+enum {
+       lt_dlerror_symbols_list
+       LT_ERROR_MAX
+};
+
+/* These functions are only useful from inside custom module loaders. */
+extern int     lt_dladderror   LT_PARAMS((const char *diagnostic));
+extern int     lt_dlseterror   LT_PARAMS((int errorcode));
+
+
+
+\f
+/* --- SOURCE COMPATIBILITY WITH OLD LIBLTDL --- */
+
+
+#ifdef LT_NON_POSIX_NAMESPACE
+#  define lt_ptr_t             lt_ptr
+#  define lt_module_t          lt_module
+#  define lt_module_open_t     lt_module_open
+#  define lt_module_close_t    lt_module_close
+#  define lt_find_sym_t                lt_find_sym
+#  define lt_dlloader_exit_t   lt_dlloader_exit
+#  define lt_dlloader_t                lt_dlloader
+#  define lt_dlloader_data_t   lt_user_data
+#endif
+
+LT_END_C_DECLS
+
+#endif /* !LTDL_H */
diff --git a/tools/ioemu/include/ltdlconf.h b/tools/ioemu/include/ltdlconf.h
new file mode 100644 (file)
index 0000000..5ffd0e7
--- /dev/null
@@ -0,0 +1,161 @@
+/* ltdlconf.h.  Generated by configure.  */
+/////////////////////////////////////////////////////////////////////////
+// $Id: ltdlconf.h.in,v 1.2 2002/10/24 21:04:38 bdenney Exp $
+//
+// The configure script reads this file and produces ltdlconf.h, which
+// tells ltdl.c how to compile.  It was copied out of the libtool package
+// but appears to have been generated by autoheader.
+/////////////////////////////////////////////////////////////////////////
+
+/* config-h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define to empty if the keyword does not work.  */
+/* #undef const */
+
+/* Define as __inline if that's what the C compiler calls it.  */
+/* #undef inline */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if you have the argz_append function.  */
+#define HAVE_ARGZ_APPEND 1
+
+/* Define if you have the argz_create_sep function.  */
+#define HAVE_ARGZ_CREATE_SEP 1
+
+/* Define if you have the argz_insert function.  */
+#define HAVE_ARGZ_INSERT 1
+
+/* Define if you have the argz_next function.  */
+#define HAVE_ARGZ_NEXT 1
+
+/* Define if you have the argz_stringify function.  */
+#define HAVE_ARGZ_STRINGIFY 1
+
+/* Define if you have the bcopy function.  */
+/* #undef HAVE_BCOPY */
+
+/* Define if you have the dlerror function.  */
+#define HAVE_DLERROR 1
+
+/* Define if you have the index function.  */
+/* #undef HAVE_INDEX */
+
+/* Define if you have the memcpy function.  */
+#define HAVE_MEMCPY 1
+
+/* Define if you have the memmove function.  */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the rindex function.  */
+/* #undef HAVE_RINDEX */
+
+/* Define if you have the strchr function.  */
+#define HAVE_STRCHR 1
+
+/* Define if you have the strcmp function.  */
+#define HAVE_STRCMP 1
+
+/* Define if you have the strrchr function.  */
+#define HAVE_STRRCHR 1
+
+/* Define if you have the <argz.h> header file.  */
+#define HAVE_ARGZ_H 1
+
+/* Define if you have the <assert.h> header file.  */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <ctype.h> header file.  */
+#define HAVE_CTYPE_H 1
+
+/* Define if you have the <dirent.h> header file.  */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <dl.h> header file.  */
+/* #undef HAVE_DL_H */
+
+/* Define if you have the <dld.h> header file.  */
+/* #undef HAVE_DLD_H */
+
+/* Define if you have the <dlfcn.h> header file.  */
+#define HAVE_DLFCN_H 1
+
+/* Define if you have the <errno.h> header file.  */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <malloc.h> header file.  */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <memory.h> header file.  */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <ndir.h> header file.  */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <stdio.h> header file.  */
+#define HAVE_STDIO_H 1
+
+/* Define if you have the <stdlib.h> header file.  */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <strings.h> header file.  */
+#define HAVE_STRINGS_H 1
+
+/* Define if you have the <sys/dir.h> header file.  */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/dl.h> header file.  */
+/* #undef HAVE_SYS_DL_H */
+
+/* Define if you have the <sys/ndir.h> header file.  */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <unistd.h> header file.  */
+#define HAVE_UNISTD_H 1
+
+/* Define to the extension used for shared libraries, say, .so.  */
+#define LTDL_SHLIB_EXT ".so"
+
+/* Define to the name of the environment variable that determines the dynamic library search path.  */
+#define LTDL_SHLIBPATH_VAR "LD_LIBRARY_PATH"
+
+/* Define to the system default library search path.  */
+#define LTDL_SYSSEARCHPATH "/lib:/usr/lib"
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.  */
+#define LTDL_OBJDIR ".libs/"
+
+/* Define if libtool can extract symbol lists from object files.  */
+#define HAVE_PRELOADED_SYMBOLS 1
+
+/* Define if you have the libdl library or equivalent.  */
+#define HAVE_LIBDL 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define if you have the libdl library or equivalent. */
+#define HAVE_LIBDL 1
+
+/* Define if you have the shl_load function. */
+/* #undef HAVE_SHL_LOAD */
+
+/* Define if you have the shl_load function. */
+/* #undef HAVE_SHL_LOAD */
+
+/* Define if you have the GNU dld library. */
+/* #undef HAVE_DLD */
+
+/* Define if dlsym() requires a leading underscode in symbol names.  */
+/* #undef NEED_USCORE */
+
+/* Define if the OS needs help to load dependent libraries for dlopen().  */
+/* #undef LTDL_DLOPEN_DEPLIBS */
+
+/* Define to a type to use for `error_t' if it is not otherwise available. */
+/* #undef error_t */
+
diff --git a/tools/ioemu/include/osdep.h b/tools/ioemu/include/osdep.h
new file mode 100644 (file)
index 0000000..a47b88d
--- /dev/null
@@ -0,0 +1,176 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: osdep.h,v 1.19 2003/08/20 06:26:27 japj Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// osdep.h
+//
+// requires Bit32u/Bit64u from config.h, size_t from stdio.h
+// 
+// Operating system dependent includes and defines for Bochs.  These 
+// declarations can be included by C or C++., but they require definition of
+// size_t beforehand.  This makes it difficult to place them into either
+// config.h or bochs.h.  If in config.h, size_t is not always available yet.
+// If in bochs.h, they can't be included by C programs so they lose.  
+//
+
+#ifndef BX_OSDEP_H
+#define BX_OSDEP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif   /* __cplusplus */
+
+//////////////////////////////////////////////////////////////////////
+// Hacks for win32, but exclude MINGW32 because it doesn't need them.
+//////////////////////////////////////////////////////////////////////
+#ifdef WIN32
+
+// Definitions that are needed for all WIN32 compilers.
+#  define ssize_t long
+
+#ifndef __MINGW32__
+#define FMT_LL "%I64"
+
+// Definitions that are needed for WIN32 compilers EXCEPT FOR
+// cygwin compiling with -mno-cygwin.  e.g. VC++.
+
+// always return regular file.
+#  define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
+#  define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)
+
+// win32 has snprintf though with different name.
+#define snprintf _snprintf
+#else    /* ifnndef __MINGW32__ */
+#define FMT_LL "%ll"
+#endif  /* ifnndef __MINGW32__ */
+#else    /* WIN32 */
+#define FMT_LL "%ll"
+#endif   /* WIN32 */
+
+// Missing defines for open
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP 0040
+#define S_IWGRP 0020
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0004
+#define S_IWOTH 0002
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions.
+// These should work on any platform that needs them.
+// 
+// A missing library function is renamed to a bx_* function, so that when
+// debugging and linking there's no confusion over which version is used.
+// Because of renaming, the bx_* replacement functions can be tested on 
+// machines which have the real library function without duplicate symbols.
+//
+// If you're considering implementing a missing library function, note 
+// that it might be cleaner to conditionally disable the function call!
+//////////////////////////////////////////////////////////////////////
+
+#if !BX_HAVE_SNPRINTF
+#define snprintf bx_snprintf
+  extern int bx_snprintf (char *s, size_t maxlen, const char *format, ...);
+#endif
+
+#if BX_HAVE_STRTOULL
+  // great, just use the usual function
+#elif BX_HAVE_STRTOUQ
+  // they have strtouq and not strtoull
+  #define strtoull strtouq
+#else
+  #define strtoull bx_strtoull
+  extern Bit64u bx_strtoull (const char *nptr, char **endptr, int baseignore);
+#endif
+
+#if !BX_HAVE_STRDUP
+#define strdup bx_strdup
+  extern char *bx_strdup(const char *str);
+#endif
+
+#if !BX_HAVE_STRREV
+#define strrev bx_strrev
+  extern char *bx_strrev(char *str);
+#endif
+
+#if !BX_HAVE_SOCKLEN_T
+// needed on MacOS X 10.1
+typedef int socklen_t;
+#endif
+
+#if !BX_HAVE_MKSTEMP
+#define mkstemp bx_mkstemp
+  extern int bx_mkstemp(char *tpl);
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions, implemented for MacOS only
+//////////////////////////////////////////////////////////////////////
+
+#if BX_WITH_MACOS
+// fd_read and fd_write are called by floppy.cc to access the Mac
+// floppy drive directly, since the MacOS doesn't have "special"
+// pathnames which map directly to IO devices
+
+int fd_read(char *buffer, Bit32u offset, Bit32u bytes);
+int fd_write(char *buffer, Bit32u offset, Bit32u bytes);
+int fd_stat(struct stat *buf);
+FILE *  fdopen(int fd, const char *type);
+
+typedef long ssize_t ;
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// New functions to replace library functions
+//   with OS-independent versions
+//////////////////////////////////////////////////////////////////////
+
+#if BX_HAVE_REALTIME_USEC
+// 64-bit time in useconds.
+extern Bit64u bx_get_realtime64_usec (void);
+#endif
+
+#ifdef WIN32
+#undef BX_HAVE_MSLEEP
+#define BX_HAVE_MSLEEP 1
+#ifndef __MINGW32__
+#define msleep(msec)   _sleep(msec)
+#else
+#define msleep(msec)   Sleep(msec)
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif   /* __cplusplus */
+
+#endif /* ifdef BX_OSDEP_H */
diff --git a/tools/ioemu/include/pc_system.h b/tools/ioemu/include/pc_system.h
new file mode 100644 (file)
index 0000000..c35c35b
--- /dev/null
@@ -0,0 +1,199 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pc_system.h,v 1.25 2003/03/02 23:59:08 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+#define BX_MAX_TIMERS 64
+#define BX_NULL_TIMER_HANDLE 10000
+
+
+#if BX_SHOW_IPS
+extern unsigned long ips_count;
+#endif
+
+
+typedef void (*bx_timer_handler_t)(void *);
+
+
+BOCHSAPI extern class bx_pc_system_c bx_pc_system;
+
+#ifdef PROVIDE_M_IPS
+extern double m_ips;
+#endif
+
+class BOCHSAPI bx_pc_system_c : private logfunctions {
+private:
+
+  // ===============================
+  // Timer oriented private features
+  // ===============================
+
+  struct {
+    bx_bool inUse;      // Timer slot is in-use (currently registered).
+    Bit64u  period;     // Timer periodocity in cpu ticks.
+    Bit64u  timeToFire; // Time to fire next (in absolute ticks).
+    bx_bool active;     // 0=inactive, 1=active.
+    bx_bool continuous; // 0=one-shot timer, 1=continuous periodicity.
+    bx_timer_handler_t funct;  // A callback function for when the
+                               //   timer fires.
+    void *this_ptr;            // The this-> pointer for C++ callbacks
+                               //   has to be stored as well.
+#define BxMaxTimerIDLen 32
+    char id[BxMaxTimerIDLen]; // String ID of timer.
+    } timer[BX_MAX_TIMERS];
+
+  unsigned   numTimers;  // Number of currently allocated timers.
+  Bit32u     currCountdown; // Current countdown ticks value (decrements to 0).
+  Bit32u     currCountdownPeriod; // Length of current countdown period.
+  Bit64u     ticksTotal; // Num ticks total since start of emulator execution.
+  Bit64u     lastTimeUsec; // Last sequentially read time in usec.
+  Bit64u     usecSinceLast; // Number of useconds claimed since then.
+
+  // A special null timer is always inserted in the timer[0] slot.  This
+  // make sure that at least one timer is always active, and that the
+  // duration is always less than a maximum 32-bit integer, so a 32-bit
+  // counter can be used for the current countdown.
+  static const Bit64u NullTimerInterval;
+  static void nullTimer(void* this_ptr);
+
+#if !defined(PROVIDE_M_IPS)
+  // This is the emulator speed, as measured in millions of
+  // x86 instructions per second that it can emulate on some hypothetically
+  // nomimal workload.
+  double     m_ips; // Millions of Instructions Per Second
+#endif
+
+  // This handler is called when the function which decrements the clock
+  // ticks finds that an event has occurred.
+  void   countdownEvent(void);
+
+public:
+
+  // ==============================
+  // Timer oriented public features
+  // ==============================
+
+  void   init_ips(Bit32u ips);
+  int    register_timer( void *this_ptr, bx_timer_handler_t, Bit32u useconds,
+                         bx_bool continuous, bx_bool active, const char *id);
+  unsigned unregisterTimer(int timerID);
+  void   start_timers(void);
+  void   activate_timer( unsigned timer_index, Bit32u useconds,
+                         bx_bool continuous );
+  void   deactivate_timer( unsigned timer_index );
+  static BX_CPP_INLINE void tick1(void) {
+#if BX_SHOW_IPS
+  {
+  extern unsigned long ips_count;
+  ips_count++;
+  }
+#endif
+    if (--bx_pc_system.currCountdown == 0) {
+      bx_pc_system.countdownEvent();
+      }
+    }
+  static BX_CPP_INLINE void tickn(Bit64u n) {
+#if BX_SHOW_IPS
+  {
+  extern unsigned long ips_count;
+  ips_count += n;
+  }
+#endif
+    while (n >= Bit64u(bx_pc_system.currCountdown)) {
+      n -= Bit64u(bx_pc_system.currCountdown);
+      bx_pc_system.currCountdown = 0;
+      bx_pc_system.countdownEvent();
+      // bx_pc_system.currCountdown is adjusted to new value by countdownevent().
+      };
+    // 'n' is not (or no longer) >= the countdown size.  We can just decrement
+    // the remaining requested ticks and continue.
+    bx_pc_system.currCountdown -= Bit32u(n);
+    }
+
+  int register_timer_ticks(void* this_ptr, bx_timer_handler_t, Bit64u ticks,
+                           bx_bool continuous, bx_bool active, const char *id);
+  void activate_timer_ticks(unsigned index, Bit64u instructions,
+                            bx_bool continuous);
+  Bit64u time_usec();
+  Bit64u time_usec_sequential();
+  static BX_CPP_INLINE Bit64u time_ticks() {
+    return bx_pc_system.ticksTotal +
+      Bit64u(bx_pc_system.currCountdownPeriod - bx_pc_system.currCountdown);
+    }
+  static BX_CPP_INLINE Bit64u getTicksTotal(void) {
+    return bx_pc_system.ticksTotal;
+    }
+
+  static BX_CPP_INLINE Bit32u  getNumCpuTicksLeftNextEvent(void) {
+    return bx_pc_system.currCountdown;
+    }
+#if BX_DEBUGGER
+  static void timebp_handler(void* this_ptr);
+#endif
+
+
+  // ===========================
+  // Non-timer oriented features
+  // ===========================
+
+  bx_bool HRQ;     // Hold Request
+  //bx_bool INTR;    // Interrupt
+
+
+    // Address line 20 control:
+    //   1 = enabled: extended memory is accessible
+    //   0 = disabled: A20 address line is forced low to simulate
+    //       an 8088 address map
+  bx_bool enable_a20;
+
+    // start out masking physical memory addresses to:
+    //   8086:      20 bits
+    //    286:      24 bits
+    //    386:      32 bits
+    // when A20 line is disabled, mask physical memory addresses to:
+    //    286:      20 bits
+    //    386:      20 bits
+    //
+  Bit32u  a20_mask;
+
+  void set_HRQ(bx_bool val);  // set the Hold ReQuest line
+  void set_INTR(bx_bool value); // set the INTR line to value
+
+  int IntEnabled( void );
+  int InterruptSignal( PCS_OP operation );
+  int ResetSignal( PCS_OP operation );
+  Bit8u  IAC(void);
+
+  bx_pc_system_c(void);
+
+  Bit32u  inp(Bit16u addr, unsigned io_len) BX_CPP_AttrRegparmN(2);
+  void    outp(Bit16u addr, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
+  void    set_enable_a20(Bit8u value) BX_CPP_AttrRegparmN(1);
+  bx_bool get_enable_a20(void);
+  void    exit(void);
+
+  };
diff --git a/tools/ioemu/include/plugin.h b/tools/ioemu/include/plugin.h
new file mode 100644 (file)
index 0000000..dabd13f
--- /dev/null
@@ -0,0 +1,323 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: plugin.h,v 1.20 2003/08/04 16:03:08 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file provides macros and types needed for plugins.  It is based on
+// the plugin.h file from plex86, but with significant changes to make
+// it work in Bochs.  
+// Plex86 is Copyright (C) 1999-2000  The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#ifndef __PLUGIN_H
+#define __PLUGIN_H
+
+#include "extplugin.h"
+
+class bx_devices_c;
+BOCHSAPI extern logfunctions  *pluginlog;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BX_PLUGIN_UNMAPPED  "unmapped"
+#define BX_PLUGIN_BIOSDEV   " biosdev"
+#define BX_PLUGIN_CMOS      "cmos"
+#define BX_PLUGIN_VGA       "vga"
+#define BX_PLUGIN_FLOPPY    "floppy"
+#define BX_PLUGIN_PARALLEL  "parallel"
+#define BX_PLUGIN_SERIAL    "serial"
+#define BX_PLUGIN_KEYBOARD  "keyboard"
+#define BX_PLUGIN_HARDDRV   "harddrv"
+#define BX_PLUGIN_DMA       "dma"
+#define BX_PLUGIN_PIC       "pic"
+#define BX_PLUGIN_PCI       "pci"
+#define BX_PLUGIN_PCI2ISA   "pci2isa"
+#define BX_PLUGIN_SB16      "sb16"
+#define BX_PLUGIN_NE2K      "ne2k"
+#define BX_PLUGIN_EXTFPUIRQ "extfpuirq"
+#define BX_PLUGIN_PCIVGA    "pcivga"
+#define BX_PLUGIN_PCIUSB    "pciusb"
+#define BX_PLUGIN_GAMEPORT  "gameport"
+
+
+#define BX_REGISTER_DEVICE_DEVMODEL(a,b,c,d) pluginRegisterDeviceDevmodel(a,b,c,d)
+
+#if BX_PLUGINS
+
+#define DEV_init_devices() {bx_devices.init(BX_MEM(0)); }
+#define DEV_reset_devices(type) {bx_devices.reset(type); }
+#define PLUG_load_plugin(name,type) {bx_load_plugin(#name,type);}
+
+#define DEV_register_ioread_handler(b,c,d,e,f)  pluginRegisterIOReadHandler(b,c,d,e,f)
+#define DEV_register_iowrite_handler(b,c,d,e,f) pluginRegisterIOWriteHandler(b,c,d,e,f)
+#define DEV_register_default_ioread_handler(b,c,d,e) pluginRegisterDefaultIOReadHandler(b,c,d,e)
+#define DEV_register_default_iowrite_handler(b,c,d,e) pluginRegisterDefaultIOWriteHandler(b,c,d,e)
+
+#define DEV_register_irq(b,c) pluginRegisterIRQ(b,c)
+#define DEV_unregister_irq(b,c) pluginUnregisterIRQ(b,c)
+
+#else
+
+#define DEV_init_devices() {bx_devices.init(BX_MEM(0)); }
+#define DEV_reset_devices(type) {bx_devices.reset(type); }
+// When plugins are off, PLUG_load_plugin will call the plugin_init function
+// directly.
+#define PLUG_load_plugin(name,type) {lib##name##_LTX_plugin_init(NULL,type,0,NULL);}
+#define DEV_register_ioread_handler(b,c,d,e,f) bx_devices.register_io_read_handler(b,c,d,e,f)
+#define DEV_register_iowrite_handler(b,c,d,e,f) bx_devices.register_io_write_handler(b,c,d,e,f)
+#define DEV_register_default_ioread_handler(b,c,d,e) bx_devices.register_default_io_read_handler(b,c,d,e)
+#define DEV_register_default_iowrite_handler(b,c,d,e) bx_devices.register_default_io_write_handler(b,c,d,e)
+#define DEV_register_irq(b,c) bx_devices.register_irq(b,c)
+#define DEV_unregister_irq(b,c) bx_devices.unregister_irq(b,c)
+
+#endif // #if BX_PLUGINS
+
+#define DEV_ioapic_present() (bx_devices.ioapic != NULL)
+
+// FIXME Do we really need pluginRegisterTimer ?
+#define DEV_register_timer(a,b,c,d,e,f) bx_pc_system.register_timer(a,b,c,d,e,f)
+
+///////// CMOS macros
+#define DEV_cmos_get_reg(a) (bx_devices.pluginCmosDevice->get_reg(a))
+#define DEV_cmos_set_reg(a,b) (bx_devices.pluginCmosDevice->set_reg(a,b))
+#define DEV_cmos_checksum() (bx_devices.pluginCmosDevice->checksum_cmos())
+#define DEV_cmos_get_timeval() (bx_devices.pluginCmosDevice->get_timeval())
+
+///////// keyboard macros
+#define DEV_mouse_motion(dx, dy, state) \
+    (bx_devices.pluginKeyboard->mouse_motion(dx, dy, state))
+#define DEV_kbd_gen_scancode(key) \
+    (bx_devices.pluginKeyboard->gen_scancode(key))
+#define DEV_kbd_paste_bytes(bytes, count) \
+    (bx_devices.pluginKeyboard->paste_bytes(bytes,count))
+#define DEV_kbd_paste_delay_changed() \
+    (bx_devices.pluginKeyboard->paste_delay_changed())
+#define DEV_mouse_enabled_changed(val) \
+    (bx_devices.pluginKeyboard->mouse_enabled_changed(val))
+
+///////// hard drive macros
+#define DEV_hd_read_handler(a, b, c) \
+    (bx_devices.pluginHardDrive->virt_read_handler(b, c))
+#define DEV_hd_write_handler(a, b, c, d) \
+    (bx_devices.pluginHardDrive->virt_write_handler(b, c, d))
+#define DEV_hd_get_first_cd_handle() \
+    (bx_devices.pluginHardDrive->get_first_cd_handle())
+#define DEV_hd_get_device_handle(a,b) \
+    (bx_devices.pluginHardDrive->get_device_handle(a,b))
+#define DEV_hd_get_cd_media_status(handle) \
+    (bx_devices.pluginHardDrive->get_cd_media_status(handle))
+#define DEV_hd_set_cd_media_status(handle, status) \
+    (bx_devices.pluginHardDrive->set_cd_media_status(handle, status))
+#define DEV_hd_close_harddrive()  bx_devices.pluginHardDrive->close_harddrive()
+#define DEV_hd_present() (bx_devices.pluginHardDrive != &bx_devices.stubHardDrive)
+
+#define DEV_bulk_io_quantum_requested() (bx_devices.bulkIOQuantumsRequested)
+#define DEV_bulk_io_quantum_transferred() (bx_devices.bulkIOQuantumsTransferred)
+#define DEV_bulk_io_host_addr() (bx_devices.bulkIOHostAddr)
+
+///////// FLOPPY macros
+#define DEV_floppy_get_media_status(drive) bx_devices.pluginFloppyDevice->get_media_status(drive)
+#define DEV_floppy_set_media_status(drive, status)  bx_devices.pluginFloppyDevice->set_media_status(drive, status)
+#define DEV_floppy_present() (bx_devices.pluginFloppyDevice != &bx_devices.stubFloppy)
+
+///////// DMA macros
+#define DEV_dma_register_8bit_channel(channel, dmaRead, dmaWrite, name) \
+  (bx_devices.pluginDmaDevice->registerDMA8Channel(channel, dmaRead, dmaWrite, name))
+#define DEV_dma_register_16bit_channel(channel, dmaRead, dmaWrite, name) \
+  (bx_devices.pluginDmaDevice->registerDMA16Channel(channel, dmaRead, dmaWrite, name))
+#define DEV_dma_unregister_channel(channel) \
+  (bx_devices.pluginDmaDevice->unregisterDMAChannel(channel))
+#define DEV_dma_set_drq(channel, val) \
+  (bx_devices.pluginDmaDevice->set_DRQ(channel, val))
+#define DEV_dma_get_tc() \
+  (bx_devices.pluginDmaDevice->get_TC())
+#define DEV_dma_raise_hlda() \
+  (bx_devices.pluginDmaDevice->raise_HLDA())
+
+///////// PIC macros
+#define DEV_pic_lower_irq(b)  (bx_devices.pluginPicDevice->lower_irq(b))
+#define DEV_pic_raise_irq(b)  (bx_devices.pluginPicDevice->raise_irq(b))
+#define DEV_pic_iac()         (bx_devices.pluginPicDevice->IAC())
+#define DEV_pic_show_pic_state() (bx_devices.pluginPicDevice->show_pic_state())
+
+///////// VGA macros
+#define DEV_vga_mem_read(addr) (bx_devices.pluginVgaDevice->mem_read(addr))
+#define DEV_vga_mem_write(addr, val) (bx_devices.pluginVgaDevice->mem_write(addr, val))
+#define DEV_vga_redraw_area(left, top, right, bottom) \
+  (bx_devices.pluginVgaDevice->redraw_area(left, top, right, bottom))
+#define DEV_vga_get_text_snapshot(rawsnap, height, width) \
+  (bx_devices.pluginVgaDevice->get_text_snapshot(rawsnap, height, width))
+#define DEV_vga_refresh() \
+  (bx_devices.pluginVgaDevice->trigger_timer(bx_devices.pluginVgaDevice))
+#define DEV_vga_set_update_interval(val) \
+  (bx_devices.pluginVgaDevice->set_update_interval(val))
+#define DEV_vga_get_actl_pal_idx(index) (bx_devices.pluginVgaDevice->get_actl_palette_idx(index))
+
+///////// PCI macros
+#define DEV_register_pci_handlers(b,c,d,e,f) \
+  (bx_devices.pluginPciBridge->register_pci_handlers(b,c,d,e,f))
+#define DEV_pci_rd_memtype(addr) bx_devices.pluginPciBridge->rd_memType(addr)
+#define DEV_pci_wr_memtype(addr) bx_devices.pluginPciBridge->wr_memType(addr)
+#define DEV_pci_print_i440fx_state() bx_devices.pluginPciBridge->print_i440fx_state()
+
+///////// NE2000 macro
+#define DEV_ne2k_print_info(file,page,reg,brief) \
+    bx_devices.pluginNE2kDevice->print_info(file,page,reg,brief)
+
+
+#if BX_HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+typedef Bit32u (*ioReadHandler_t)(void *, Bit32u, unsigned);
+typedef void   (*ioWriteHandler_t)(void *, Bit32u, Bit32u, unsigned);
+
+extern plugin_t *plugins;
+
+typedef struct _device_t
+{
+    const char *name;
+    plugin_t *plugin;
+    void (*device_init_mem)(BX_MEM_C *);
+    void (*device_init_dev)();
+    void (*device_reset)(unsigned);
+    void (*device_load_state)();
+    void (*device_save_state)();
+
+    int use_devmodel_interface;  // BBD hack
+    class bx_devmodel_c *devmodel;  // BBD hack
+
+    struct _device_t *next;
+} device_t;
+
+
+extern device_t *devices;
+
+void plugin_startup (void);
+void plugin_load (char *name, char *args, plugintype_t);
+plugin_t *plugin_unload (plugin_t *plugin);
+void plugin_init_all (void);
+void plugin_fini_all (void);
+
+/* === Device Stuff === */
+typedef void (*deviceInitMem_t)(BX_MEM_C *);
+typedef void (*deviceInitDev_t)(void);
+typedef void (*deviceReset_t)(unsigned);
+typedef void (*deviceLoad_t)(void);
+typedef void (*deviceSave_t)(void);
+
+BOCHSAPI void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *dev, char *name);
+BOCHSAPI bx_bool pluginDevicePresent(char *name);
+
+/* === IO port stuff === */
+BOCHSAPI extern int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+                                unsigned base, const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+                                 unsigned base, const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+                                const char *name, Bit8u mask);
+BOCHSAPI extern int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+                                 const char *name, Bit8u mask);
+
+/* === A20 enable line stuff === */
+BOCHSAPI extern unsigned (*pluginGetA20E)(void);
+BOCHSAPI extern void     (*pluginSetA20E)(unsigned val);
+
+/* === IRQ stuff === */
+BOCHSAPI extern void  (*pluginRegisterIRQ)(unsigned irq, const char *name);
+BOCHSAPI extern void  (*pluginUnregisterIRQ)(unsigned irq, const char *name);
+
+/* === Floppy stuff ===*/
+BOCHSAPI extern unsigned (* pluginFloppyGetMediaStatus)(unsigned drive);
+BOCHSAPI extern unsigned (* pluginFloppySetMediaStatus)(unsigned drive, unsigned status);
+
+/* === VGA stuff === */
+BOCHSAPI extern void (* pluginVGARedrawArea)(unsigned x0, unsigned y0,
+                 unsigned width, unsigned height);
+BOCHSAPI extern Bit8u (* pluginVGAMemRead)(Bit32u addr);
+BOCHSAPI extern void  (* pluginVGAMemWrite)(Bit32u addr, Bit8u value);
+BOCHSAPI extern void  (* pluginVGAGetTextSnapshot)(Bit8u **text_snapshot, 
+                         unsigned *txHeight, unsigned *txWidth);
+BOCHSAPI extern void  (* pluginVGARefresh)(void *);
+BOCHSAPI extern void  (* pluginVGASetUpdateInterval)(unsigned);
+BOCHSAPI extern Bit8u (* pluginVGAGetActlPaletteIdx)(Bit8u index);
+
+/* === Timer stuff === */
+BOCHSAPI extern int      (*pluginRegisterTimer)(void *this_ptr, void (*funct)(void *),
+                             Bit32u useconds, bx_bool continuous,
+                             bx_bool active, const char *name);
+
+BOCHSAPI extern void     (*pluginActivateTimer)(unsigned id, Bit32u usec, bx_bool continuous);
+BOCHSAPI extern void     (*pluginDeactivateTimer)(unsigned id);
+
+/* === HRQ stuff === */
+BOCHSAPI extern void     (*pluginSetHRQ)(unsigned val);
+BOCHSAPI extern void     (*pluginSetHRQHackCallback)( void (*callback)(void) );
+
+/* === Reset stuff === */
+BOCHSAPI extern void     (*pluginResetSignal)(unsigned sig);
+
+/* === PCI stuff === */
+BOCHSAPI extern bx_bool  (*pluginRegisterPCIDevice)(void *this_ptr,
+                             Bit32u (*bx_pci_read_handler)(void *, Bit8u, unsigned),
+                             void(*bx_pci_write_handler)(void *, Bit8u, Bit32u, unsigned),
+                             Bit8u devfunc, const char *name);
+BOCHSAPI extern Bit8u    (*pluginRd_memType)(Bit32u addr);
+BOCHSAPI extern Bit8u    (*pluginWr_memType)(Bit32u addr);
+
+void plugin_abort (void);
+
+int bx_load_plugin (const char *name, plugintype_t type);
+extern void bx_init_plugins (void);
+extern void bx_reset_plugins (unsigned);
+
+// every plugin must define these, within the extern"C" block, so that
+// a non-mangled function symbol is available in the shared library.
+void plugin_fini(void);
+int plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[]);
+
+// still in extern "C"
+#define DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(mod) \
+  int lib##mod##_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[]); \
+  void lib##mod##_LTX_plugin_fini(void);
+  
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(harddrv)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(keyboard)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(serial)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(unmapped)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(biosdev)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(cmos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(dma)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pic)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(vga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(floppy)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(parallel)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pci2isa)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pcivga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(pciusb)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sb16)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(ne2k)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(extfpuirq)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(gameport)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(amigaos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(beos)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(carbon)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(macintosh)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(nogui)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(rfb)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(sdl)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(svga)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(term)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(win32)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(wx)
+DECLARE_PLUGIN_INIT_FINI_FOR_MODULE(x)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PLUGIN_H */
diff --git a/tools/ioemu/include/state_file.h b/tools/ioemu/include/state_file.h
new file mode 100644 (file)
index 0000000..7cef477
--- /dev/null
@@ -0,0 +1,61 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: state_file.h,v 1.5 2002/10/24 21:05:00 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Classes for helping to make checkpoints of the emulator state.
+
+#ifndef _STATE_FILE_H
+#define _STATE_FILE_H
+#include <stdio.h>
+#include <stddef.h>
+
+
+class BOCHSAPI state_file {
+  void init(void);
+public:
+  FILE *file;
+  class logfunctions *log;
+
+  FILE *get_handle();
+  void write(Bit8u);
+  void write(Bit16u);
+  void write(Bit32u);
+  void write(Bit64u);
+  void write(const void*, size_t);
+  void read(Bit8u &);
+  void read(Bit16u &);
+  void read(Bit32u &);
+  void read(Bit64u &);
+  void read(void *, size_t);
+  void write_check(const char *);
+  void read_check (const char *);
+
+  state_file (const char *name, const char *options);
+  state_file (FILE *f);
+  ~state_file();
+};
+
+#endif  // #ifndef _STATE_FILE_H
diff --git a/tools/ioemu/iodev/Makefile b/tools/ioemu/iodev/Makefile
new file mode 100644 (file)
index 0000000..5c251de
--- /dev/null
@@ -0,0 +1,15 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS=$(patsubst %.cc,%.o,$(wildcard *.cc))
+BXLIBS = ../gui/libgui.a ../memory/libmemory.a  
+LDLIBS= $(BXLIBS) -L/usr/X11R6/lib -lX11 -lXpm -lstdc++ -L ../../../tools/libxc -L ../../../tools/libxutil -lxc -lxutil
+
+all: device-model
+
+device-model: $(OBJS) $(BXLIBS)
+       $(LINK.o) $(OBJS) $(LOADLIBES) $(LDLIBS) -o $@
+
+include $(TOPDIR)/mk/helix.mk
+
+install::
+       install device-model $(prefix)/usr/sbin
diff --git a/tools/ioemu/iodev/aspi-win32.h b/tools/ioemu/iodev/aspi-win32.h
new file mode 100644 (file)
index 0000000..afa62d1
--- /dev/null
@@ -0,0 +1,210 @@
+//
+// iodev/aspi-win32.h
+// $Id: aspi-win32.h,v 1.2 2001/06/25 12:52:37 bdenney Exp $
+//
+// This file was copied from cdrecord 1.9 under libscg/scg/aspi-win32.h.
+// The only modification is related to use of the PACKED keyword.  
+// 
+
+#ifndef __ASPI_WIN32_H_
+#define __ASPI_WIN32_H_
+
+#include <windows.h>
+
+#ifndef PACKED
+// It seems that VC++ has no PACKED keyword but Cygwin does.  We can just
+// define PACKED to be empty if it's not already defined by the system 
+// headers.
+#define PACKED /* empty */
+#endif
+
+/***************************************************************************
+ ** SCSI MISCELLANEOUS EQUATES
+ ***************************************************************************/
+#define SENSE_LEN                 14     /* Default sense buffer length    */
+#define SRB_DIR_SCSI              0x00   /* Direction determined by SCSI   */
+#define SRB_POSTING               0x01   /* Enable ASPI posting            */
+#define SRB_ENABLE_RESIDUAL_COUNT 0x04   /* Enable residual byte count     */
+                                         /* reporting                      */
+#define SRB_DIR_IN                0x08   /* Transfer from SCSI target to   */
+                                         /* host                           */
+#define SRB_DIR_OUT               0x10   /* Transfer from host to SCSI     */
+                                         /* target                         */
+#define SRB_EVENT_NOTIFY          0x40   /* Enable ASPI event notification */
+#define RESIDUAL_COUNT_SUPPORTED  0x02   /* Extended buffer flag           */
+#define MAX_SRB_TIMEOUT       1080001u   /* 30 hour maximum timeout in sec */
+#define DEFAULT_SRB_TIMEOUT   1080001u   /* use max.timeout by default     */
+
+/***************************************************************************
+ ** ASPI command definitions
+ ***************************************************************************/
+#define SC_HA_INQUIRY             0x00   /* Host adapter inquiry           */
+#define SC_GET_DEV_TYPE           0x01   /* Get device type                */
+#define SC_EXEC_SCSI_CMD          0x02   /* Execute SCSI command           */
+#define SC_ABORT_SRB              0x03   /* Abort an SRB                   */
+#define SC_RESET_DEV              0x04   /* SCSI bus device reset          */
+#define SC_SET_HA_PARMS           0x05   /* Set HA parameters              */
+#define SC_GET_DISK_INFO          0x06   /* Get Disk                       */
+#define SC_RESCAN_SCSI_BUS        0x07   /* Rebuild SCSI device map        */
+#define SC_GETSET_TIMEOUTS        0x08   /* Get/Set target timeouts        */
+
+
+/***************************************************************************
+ ** SRB Status
+ ***************************************************************************/
+#define SS_PENDING                0x00   /* SRB being processed            */
+#define SS_COMP                   0x01   /* SRB completed without error    */
+#define SS_ABORTED                0x02   /* SRB aborted                    */
+#define SS_ABORT_FAIL             0x03   /* Unable to abort SRB            */
+#define SS_ERR                    0x04   /* SRB completed with error       */
+#define SS_INVALID_CMD            0x80   /* Invalid ASPI command           */
+#define SS_INVALID_HA             0x81   /* Invalid host adapter number    */
+#define SS_NO_DEVICE              0x82   /* SCSI device not installed      */
+#define SS_INVALID_SRB            0xE0   /* Invalid parameter set in SRB   */
+#define SS_OLD_MANAGER            0xE1   /* ASPI manager doesn't support   */
+                                         /* windows                        */
+#define SS_BUFFER_ALIGN           0xE1   /* Buffer not aligned (replaces   */
+                                         /* SS_OLD_MANAGER in Win32)       */
+#define SS_ILLEGAL_MODE           0xE2   /* Unsupported Windows mode       */
+#define SS_NO_ASPI                0xE3   /* No ASPI managers               */
+#define SS_FAILED_INIT            0xE4   /* ASPI for windows failed init   */
+#define SS_ASPI_IS_BUSY           0xE5   /* No resources available to      */
+                                         /* execute command                */
+#define SS_BUFFER_TO_BIG          0xE6   /* Buffer size too big to handle  */
+#define SS_BUFFER_TOO_BIG         0xE6   /* Correct spelling of 'too'      */
+#define SS_MISMATCHED_COMPONENTS  0xE7   /* The DLLs/EXEs of ASPI don't    */
+                                         /* version check                  */
+#define SS_NO_ADAPTERS            0xE8   /* No host adapters to manager    */
+#define SS_INSUFFICIENT_RESOURCES 0xE9   /* Couldn't allocate resources    */
+                                         /* needed to init                 */
+#define SS_ASPI_IS_SHUTDOWN       0xEA   /* Call came to ASPI after        */
+                                         /* PROCESS_DETACH                 */
+#define SS_BAD_INSTALL            0xEB   /* The DLL or other components    */
+                                         /* are installed wrong            */
+
+/***************************************************************************
+ ** Host Adapter Status
+ ***************************************************************************/
+#define HASTAT_OK                 0x00   /* No error detected by HA        */
+#define HASTAT_SEL_TO             0x11   /* Selection Timeout              */
+#define HASTAT_DO_DU              0x12   /* Data overrun/data underrun     */
+#define HASTAT_BUS_FREE           0x13   /* Unexpected bus free            */
+#define HASTAT_PHASE_ERR          0x14   /* Target bus phase sequence      */
+#define HASTAT_TIMEOUT            0x09   /* Timed out while SRB was        */
+                                         /* waiting to be processed        */
+#define HASTAT_COMMAND_TIMEOUT    0x0B   /* Adapter timed out while        */
+                                         /* processing SRB                 */
+#define HASTAT_MESSAGE_REJECT     0x0D   /* While processing the SRB, the  */
+                                         /* adapter received a MESSAGE     */
+#define HASTAT_BUS_RESET          0x0E   /* A bus reset was detected       */
+#define HASTAT_PARITY_ERROR       0x0F   /* A parity error was detected    */
+#define HASTAT_REQUEST_SENSE_FAILED 0x10 /* The adapter failed in issuing  */
+
+/***************************************************************************
+ ** SRB - HOST ADAPTER INQUIRIY - SC_HA_INQUIRY (0)
+ ***************************************************************************/
+typedef struct {
+  BYTE     SRB_Cmd;           /* 00/000 ASPI command code == SC_HA_INQUIRY */
+  BYTE     SRB_Status;        /* 01/001 ASPI command status byte           */
+  BYTE     SRB_HaId;          /* 02/002 ASPI host adapter number           */
+  BYTE     SRB_Flags;         /* 03/003 ASPI request flags                 */
+  DWORD    SRB_Hdr_Rsvd;      /* 04/004 Reserved, must = 0                 */
+  BYTE     HA_Count;          /* 08/008 Number of host adapters present    */
+  BYTE     HA_SCSI_ID;        /* 09/009 SCSI ID of host adapter            */
+  BYTE     HA_ManagerId[16];  /* 0a/010 String describing the manager      */
+  BYTE     HA_Identifier[16]; /* 1a/026 String describing the host adapter */
+  BYTE     HA_Unique[16];     /* 2a/042 Host Adapter Unique parameters     */
+  WORD     HA_Rsvd1;          /* 3a/058 Reserved, must = 0                 */
+} PACKED SRB_HAInquiry, *PSRB_HAInquiry, FAR *LPSRB_HAInquiry;
+
+
+/***************************************************************************
+ ** SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1)
+ ***************************************************************************/
+typedef struct
+{
+  BYTE     SRB_Cmd;           /* 00/000 ASPI cmd code == SC_GET_DEV_TYPE   */
+  BYTE     SRB_Status;        /* 01/001 ASPI command status byte           */
+  BYTE     SRB_HaId;          /* 02/002 ASPI host adapter number           */
+  BYTE     SRB_Flags;         /* 03/003 Reserved, must = 0                 */
+  DWORD    SRB_Hdr_Rsvd;      /* 04/004 Reserved, must = 0                 */
+  BYTE     SRB_Target;        /* 08/008 Target's SCSI ID                   */
+  BYTE     SRB_Lun;           /* 09/009 Target's LUN number                */
+  BYTE     SRB_DeviceType;    /* 0a/010 Target's peripheral device type    */
+  BYTE     SRB_Rsvd1;         /* 0b/011 Reserved, must = 0                 */
+} PACKED SRB_GDEVBlock, *PSRB_GDEVBlock, FAR *LPSRB_GDEVBlock;
+
+
+/***************************************************************************
+ ** SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2)
+ ***************************************************************************/
+typedef struct
+{
+  BYTE     SRB_Cmd;           /* 00/000 ASPI cmd code == SC_EXEC_SCSI_CMD  */
+  BYTE     SRB_Status;        /* 01/001 ASPI command status byte           */
+  BYTE     SRB_HaId;          /* 02/002 ASPI host adapter number           */
+  BYTE     SRB_Flags;         /* 03/003 Reserved, must = 0                 */
+  DWORD    SRB_Hdr_Rsvd;      /* 04/004 Reserved, must = 0                 */
+  BYTE     SRB_Target;        /* 08/008 Target's SCSI ID                   */
+  BYTE     SRB_Lun;           /* 09/009 Target's LUN                       */
+  WORD     SRB_Rsvd1;         /* 0a/010 Reserved for alignment             */
+  DWORD    SRB_BufLen;        /* 0c/012 Data Allocation Length             */
+  BYTE FAR *SRB_BufPointer;   /* 10/016 Data Buffer Pointer                */
+  BYTE     SRB_SenseLen;      /* 14/020 Sense Allocation Length            */
+  BYTE     SRB_CDBLen;        /* 15/021 CDB Length                         */
+  BYTE     SRB_HaStat;        /* 16/022 Host Adapter Status                */
+  BYTE     SRB_TargStat;      /* 17/023 Target Status                      */
+  VOID FAR *SRB_PostProc;     /* 18/024 Post routine                       */
+  BYTE     SRB_Rsvd2[20];     /* 1c/028 Reserved, must = 0                 */
+  BYTE     CDBByte[16];       /* 30/048 SCSI CDB                           */
+  BYTE SenseArea[SENSE_LEN+2]; /* 40/064 Request Sense buffer              */
+} PACKED SRB_ExecSCSICmd, *PSRB_ExecSCSICmd, FAR *LPSRB_ExecSCSICmd;
+
+
+typedef struct
+{
+  BYTE     SRB_Cmd;           /* 00/000 ASPI cmd code == SC_ABORT_SRB      */
+  BYTE     SRB_Status;        /* 01/001 ASPI command status byte           */
+  BYTE     SRB_HaId;          /* 02/002 ASPI host adapter number           */
+  BYTE     SRB_Flags;         /* 03/003 Reserved, must = 0                 */
+  DWORD    SRB_Hdr_Rsvd;      /* 04/004 Reserved, must = 0                 */
+  void     *SRB_ToAbort;      /* 08/008 Pointer to SRB to abort            */
+} PACKED SRB_Abort, *PSRB_Abort, FAR *LPSRB_Abort;
+
+
+/***************************************************************************
+ ** SRB - BUS DEVICE RESET - SC_RESET_DEV (4)
+ ***************************************************************************/
+typedef struct
+{
+  BYTE     SRB_Cmd;           /* 00/000 ASPI cmd code == SC_RESET_DEV      */
+  BYTE     SRB_Status;        /* 01/001 ASPI command status byte           */
+  BYTE     SRB_HaId;          /* 02/002 ASPI host adapter number           */
+  DWORD    SRB_Flags;        /* 04/004 Reserved                           */
+  BYTE     SRB_Target;        /* 08/008 Target's SCSI ID                   */
+  BYTE     SRB_Lun;           /* 09/009 Target's LUN number                */
+  BYTE     SRB_Rsvd1[12];     /* 0A/010 Reserved for alignment             */
+  BYTE     SRB_HaStat;        /* 16/022 Host Adapter Status                */
+  BYTE     SRB_TargStat;      /* 17/023 Target Status                      */
+  VOID FAR *SRB_PostProc;     /* 18/024 Post routine                       */
+  BYTE     SRB_Rsvd2[36];     /* 1C/028 Reserved, must = 0                 */
+} SRB_BusDeviceReset, *PSRB_BusDeviceReset, FAR *LPSRB_BusDeviceReset;
+
+typedef struct tag_ASPI32BUFF
+{
+  PBYTE     AB_BufPointer;
+  DWORD     AB_BufLen;
+  DWORD     AB_ZeroFill;
+  DWORD     AB_Reserved;
+} PACKED ASPI32BUFF, *PASPI32BUFF, FAR *LPASPI32BUFF;
+
+typedef struct 
+{
+  BYTE      SRB_Cmd;
+  BYTE      SRB_Status;
+  BYTE      SRB_HaId;
+  BYTE      SRB_Flags;
+  DWORD     SRB_Hdr_Rsvd;
+} SRB, *PSRB, FAR *LPSRB;
+
+#endif
diff --git a/tools/ioemu/iodev/biosdev.cc b/tools/ioemu/iodev/biosdev.cc
new file mode 100644 (file)
index 0000000..d4a6ef2
--- /dev/null
@@ -0,0 +1,212 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: biosdev.cc,v 1.7 2003/12/08 19:36:23 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Here are the virtual ports use to display messages from the bioses :
+//
+//  0x0400 : rombios Panic port with message
+//  0x0401 : rombios Panic port with line number
+//  0x0402 : rombios Info port with message
+//  0x0403 : rombios Debug port with message
+//
+//  0x0500 : vgabios Info port with message
+//  0x0501 : vgabios Panic port with message
+//  0x0502 : vgabios Panic port with line number
+//  0x0503 : vgabios Debug port with message
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+bx_biosdev_c *theBiosDevice;
+
+  int
+libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theBiosDevice = new bx_biosdev_c ();
+  bx_devices.pluginBiosDevice = theBiosDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
+  return(0); // Success
+}
+
+  void
+libbiosdev_LTX_plugin_fini(void)
+{
+}
+
+logfunctions  *bioslog;
+logfunctions  *vgabioslog;
+
+bx_biosdev_c::bx_biosdev_c(void)
+{
+  bioslog = new logfunctions();
+  bioslog->put("BIOS");
+  bioslog->settype(BIOSLOG);
+  s.bios_message_i = 0;
+
+  vgabioslog = new logfunctions();
+  vgabioslog->put("VBIOS");
+  vgabioslog->settype(BIOSLOG);
+  s.vgabios_message_i = 0;
+}
+
+bx_biosdev_c::~bx_biosdev_c(void)
+{
+    if ( bioslog != NULL )
+    {
+        delete bioslog;
+        bioslog = NULL;
+    }
+
+    if ( vgabioslog != NULL )
+    {
+        delete vgabioslog;
+        vgabioslog = NULL;
+    }
+}
+
+  void
+bx_biosdev_c::init(void)
+{
+  DEV_register_iowrite_handler(this, write_handler, 0x0400, "Bios Panic Port 1", 3);
+  DEV_register_iowrite_handler(this, write_handler, 0x0401, "Bios Panic Port 2", 3);
+  DEV_register_iowrite_handler(this, write_handler, 0x0403, "Bios Debug Port", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios Info Port", 1);
+
+  DEV_register_iowrite_handler(this, write_handler, 0x0501, "VGABios Panic Port 1", 3);
+  DEV_register_iowrite_handler(this, write_handler, 0x0502, "VGABios Panic Port 2", 3);
+  DEV_register_iowrite_handler(this, write_handler, 0x0503, "VGABios Debug Port", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
+}
+
+  void
+bx_biosdev_c::reset(unsigned type)
+{
+}
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_biosdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_BIOS_SMF
+  bx_biosdev_c *class_ptr = (bx_biosdev_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_biosdev_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_BIOS_SMF
+  UNUSED(io_len);
+
+
+  switch (address) {
+    // 0x400-0x401 are used as panic ports for the rombios
+    case 0x0401:
+      if (BX_BIOS_THIS s.bios_message_i > 0) {
+       // if there are bits of message in the buffer, print them as the
+       // panic message.  Otherwise fall into the next case.
+       if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE)
+         BX_BIOS_THIS s.bios_message_i = BX_BIOS_MESSAGE_SIZE-1;
+        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i] = 0;
+       BX_BIOS_THIS s.bios_message_i = 0;
+        bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
+       break;
+      }
+    case 0x0400:
+      bioslog->panic("BIOS panic at rombios.c, line %d", value);
+      break;
+
+    // 0x0402 is used as the info port for the rombios
+    // 0x0403 is used as the debug port for the rombios
+    case 0x0402:
+    case 0x0403:
+      BX_BIOS_THIS s.bios_message[BX_BIOS_THIS s.bios_message_i] =
+        (Bit8u) value;
+      BX_BIOS_THIS s.bios_message_i ++;
+      if ( BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
+        BX_BIOS_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
+        BX_BIOS_THIS s.bios_message_i = 0;
+       if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
+       else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
+       }
+      else if ((value & 0xff) == '\n') {
+        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i - 1 ] = 0;
+        BX_BIOS_THIS s.bios_message_i = 0;
+       if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
+       else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
+        }
+      break;
+
+    // 0x501-0x502 are used as panic ports for the vgabios
+    case 0x0502:
+      if (BX_BIOS_THIS s.vgabios_message_i > 0) {
+       // if there are bits of message in the buffer, print them as the
+       // panic message.  Otherwise fall into the next case.
+       if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE)
+         BX_BIOS_THIS s.vgabios_message_i = BX_BIOS_MESSAGE_SIZE-1;
+        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i] = 0;
+       BX_BIOS_THIS s.vgabios_message_i = 0;
+        vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
+       break;
+      }
+    case 0x0501:
+      vgabioslog->panic("BIOS panic at rombios.c, line %d", value);
+      break;
+
+    // 0x0500 is used as the message port for the vgabios
+    case 0x0500:
+    case 0x0503:
+      BX_BIOS_THIS s.vgabios_message[BX_BIOS_THIS s.vgabios_message_i] =
+        (Bit8u) value;
+      BX_BIOS_THIS s.vgabios_message_i ++;
+      if ( BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
+        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
+        BX_BIOS_THIS s.vgabios_message_i = 0;
+        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
+        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
+        }
+      else if ((value & 0xff) == '\n') {
+        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i - 1 ] = 0;
+        BX_BIOS_THIS s.vgabios_message_i = 0;
+        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
+        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
+        }
+      break;
+
+    default:
+           break;
+    }
+}
diff --git a/tools/ioemu/iodev/biosdev.h b/tools/ioemu/iodev/biosdev.h
new file mode 100644 (file)
index 0000000..7cd9873
--- /dev/null
@@ -0,0 +1,63 @@
+
+// $Id: biosdev.h,v 1.3 2002/10/24 21:07:09 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#define BX_BIOS_MESSAGE_SIZE 80
+
+
+#if BX_USE_BIOS_SMF
+#  define BX_BIOS_SMF  static
+#  define BX_BIOS_THIS theBiosDevice->
+#else
+#  define BX_BIOS_SMF
+#  define BX_BIOS_THIS this->
+#endif
+
+
+class bx_biosdev_c : public bx_devmodel_c {
+public:
+  bx_biosdev_c(void);
+  ~bx_biosdev_c(void);
+
+  virtual void init(void);
+  virtual void reset (unsigned type);
+
+private:
+
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_BIOS_SMF
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+  struct {
+    Bit8u bios_message[BX_BIOS_MESSAGE_SIZE];
+    unsigned int bios_message_i;
+
+    Bit8u vgabios_message[BX_BIOS_MESSAGE_SIZE];
+    unsigned int vgabios_message_i;
+    } s;  // state information
+
+  };
diff --git a/tools/ioemu/iodev/cdrom.cc b/tools/ioemu/iodev/cdrom.cc
new file mode 100644 (file)
index 0000000..2b78e8d
--- /dev/null
@@ -0,0 +1,1338 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdrom.cc,v 1.66 2003/12/08 23:49:48 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// These are the low-level CDROM functions which are called
+// from 'harddrv.cc'.  They effect the OS specific functionality
+// needed by the CDROM emulation in 'harddrv.cc'.  Mostly, just
+// ioctl() calls and such.  Should be fairly easy to add support
+// for your OS if it is not supported yet.
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_SUPPORT_CDROM
+
+#define LOG_THIS /* no SMF tricks here, not needed */
+
+extern "C" {
+#include <errno.h>
+}
+
+#ifdef __linux__
+extern "C" {
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+// I use the framesize in non OS specific code too
+#define BX_CD_FRAMESIZE CD_FRAMESIZE
+}
+
+#elif defined(__GNU__) || (defined(__CYGWIN32__) && !defined(WIN32))
+extern "C" {
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+}
+
+#elif BX_WITH_MACOS
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+
+#elif defined(__sun)
+extern "C" {
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/cdio.h>
+#define BX_CD_FRAMESIZE CDROM_BLK_2048
+}
+
+#elif defined(__DJGPP__)
+extern "C" {
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048
+}
+
+#elif defined(__BEOS__)
+#include "cdrom_beos.h"
+#define BX_CD_FRAMESIZE 2048
+
+#elif (defined (__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__))
+// OpenBSD pre version 2.7 may require extern "C" { } structure around
+// all the includes, because the i386 sys/disklabel.h contains code which 
+// c++ considers invalid.
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/cdio.h>
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+// ntohl(x) et al have been moved out of sys/param.h in FreeBSD 5
+#include <netinet/in.h>
+
+// XXX
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE   2048
+
+#elif defined(__APPLE__)
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <dev/disk.h>
+#include <errno.h>
+#include <paths.h>
+#include <sys/param.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+// These definitions were taken from mount_cd9660.c
+// There are some similar definitions in IOCDTypes.h
+// however there seems to be some dissagreement in 
+// the definition of CDTOC.length
+struct _CDMSF {
+       u_char   minute;
+       u_char   second;
+       u_char   frame;
+};
+
+#define MSF_TO_LBA(msf)                \
+       (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
+
+struct _CDTOC_Desc {
+       u_char        session;
+       u_char        ctrl_adr;  /* typed to be machine and compiler independent */
+       u_char        tno;
+       u_char        point;
+       struct _CDMSF  address;
+       u_char        zero;
+       struct _CDMSF  p;
+};
+
+struct _CDTOC {
+       u_short            length;  /* in native cpu endian */
+       u_char             first_session;
+       u_char             last_session;
+       struct _CDTOC_Desc  trackdesc[1];
+};
+
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator, mach_port_t *masterPort );
+static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator, char *deviceFilePath, CFIndex maxPathSize );
+//int OpenDrive( const char *deviceFilePath );
+static struct _CDTOC * ReadTOC( const char * devpath );
+
+static char CDDevicePath[ MAXPATHLEN ];
+
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE   2048
+
+#elif defined(WIN32)
+// windows.h included by bochs.h
+#include <winioctl.h>
+#include "aspi-win32.h"
+#include "scsidefs.h"
+
+DWORD (*GetASPI32SupportInfo)(void);
+DWORD (*SendASPI32Command)(LPSRB);
+BOOL  (*GetASPI32Buffer)(PASPI32BUFF);
+BOOL  (*FreeASPI32Buffer)(PASPI32BUFF);
+BOOL  (*TranslateASPI32Address)(PDWORD,PDWORD);
+DWORD (*GetASPI32DLLVersion)(void);
+
+
+static BOOL bUseASPI = FALSE;
+static BOOL bHaveDev;
+static UINT cdromCount = 0;
+static HINSTANCE hASPI = NULL;
+
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE   2048
+
+#else // all others (Irix, Tru64)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#define BX_CD_FRAMESIZE 2048
+#define CD_FRAMESIZE 2048 
+#endif
+
+#include <stdio.h>
+
+#ifdef __APPLE__
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator,
+                                          mach_port_t *masterPort )
+{
+  kern_return_t     kernResult;
+  CFMutableDictionaryRef     classesToMatch;
+  kernResult = IOMasterPort( bootstrap_port, masterPort );
+  if ( kernResult != KERN_SUCCESS )
+    {
+      fprintf ( stderr, "IOMasterPort returned %d\n", kernResult );
+      return kernResult;
+    }
+  // CD media are instances of class kIOCDMediaClass.
+  classesToMatch = IOServiceMatching( kIOCDMediaClass );
+  if ( classesToMatch == NULL )
+    fprintf ( stderr, "IOServiceMatching returned a NULL dictionary.\n" );
+  else
+    {
+      // Each IOMedia object has a property with key kIOMediaEjectableKey
+      // which is true if the media is indeed ejectable. So add property
+      // to CFDictionary for matching.
+      CFDictionarySetValue( classesToMatch,
+                            CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+    }
+  kernResult = IOServiceGetMatchingServices( *masterPort,
+                                             classesToMatch, mediaIterator );
+  if ( (kernResult != KERN_SUCCESS) || (*mediaIterator == NULL) ) 
+    fprintf( stderr, "No ejectable CD media found.\n kernResult = %d\n", kernResult );
+
+  return kernResult;
+}
+
+
+static kern_return_t GetDeviceFilePath( io_iterator_t mediaIterator,
+                                       char *deviceFilePath, CFIndex maxPathSize )
+{
+  io_object_t nextMedia;
+  kern_return_t kernResult = KERN_FAILURE;
+  nextMedia = IOIteratorNext( mediaIterator );
+  if ( nextMedia == NULL )
+    {
+      *deviceFilePath = '\0';
+    }
+  else
+    {
+      CFTypeRef    deviceFilePathAsCFString;
+      deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(
+                                                                 nextMedia, CFSTR( kIOBSDNameKey ),
+                                                                 kCFAllocatorDefault, 0 );
+      *deviceFilePath = '\0';
+      if ( deviceFilePathAsCFString )
+        {
+          size_t devPathLength = strlen( _PATH_DEV );
+          strcpy( deviceFilePath, _PATH_DEV );
+          if ( CFStringGetCString( (const __CFString *) deviceFilePathAsCFString,
+                                   deviceFilePath + devPathLength,
+                                   maxPathSize - devPathLength,
+                                   kCFStringEncodingASCII ) )
+            {
+              // fprintf( stderr, "BSD path: %s\n", deviceFilePath );
+              kernResult = KERN_SUCCESS;
+            }
+          CFRelease( deviceFilePathAsCFString );
+        }
+    }
+  IOObjectRelease( nextMedia );
+  return kernResult;
+}
+
+
+static int OpenDrive( const char *deviceFilePath )
+{
+
+  int fileDescriptor;
+
+  fileDescriptor = open( deviceFilePath, O_RDONLY );
+  if ( fileDescriptor == -1 )
+    fprintf( stderr, "Error %d opening device %s.\n", errno, deviceFilePath );
+  return fileDescriptor;
+
+}
+
+static struct _CDTOC * ReadTOC( const char * devpath ) {
+
+  struct _CDTOC * toc_p = NULL;
+  io_iterator_t iterator = 0;
+  io_registry_entry_t service = 0;
+  CFDictionaryRef properties = 0;
+  CFDataRef data = 0;
+  mach_port_t port = 0;
+  char * devname;
+  
+  if (( devname = strrchr( devpath, '/' )) != NULL ) {
+    ++devname;
+  }
+  else {
+    devname = (char *) devpath;
+  }
+
+  if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS ) {
+    fprintf( stderr, "IOMasterPort failed\n" );
+    goto Exit;
+  }
+
+  if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
+                                    &iterator ) != KERN_SUCCESS ) {
+    fprintf( stderr, "IOServiceGetMatchingServices failed\n" );
+    goto Exit;
+  }
+  
+  service = IOIteratorNext( iterator );
+
+  IOObjectRelease( iterator );
+
+  iterator = 0;
+
+  while ( service && !IOObjectConformsTo( service, "IOCDMedia" )) {
+    if ( IORegistryEntryGetParentIterator( service, kIOServicePlane,
+                                          &iterator ) != KERN_SUCCESS ) {
+      fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
+      goto Exit;
+    }
+
+    IOObjectRelease( service );
+    service = IOIteratorNext( iterator );
+    IOObjectRelease( iterator );
+
+  }
+
+  if ( service == NULL ) {
+    fprintf( stderr, "CD media not found\n" );
+    goto Exit;
+  }
+
+  if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
+                                         kCFAllocatorDefault,
+                                         kNilOptions ) != KERN_SUCCESS ) {
+    fprintf( stderr, "IORegistryEntryGetParentIterator failed\n" );
+    goto Exit;
+  }
+
+  data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR(kIOCDMediaTOCKey) );
+  if ( data == NULL ) {
+    fprintf( stderr, "CFDictionaryGetValue failed\n" );
+    goto Exit;
+  }
+  else {
+
+    CFRange range;
+    CFIndex buflen;
+
+    buflen = CFDataGetLength( data ) + 1;
+    range = CFRangeMake( 0, buflen );
+    toc_p = (struct _CDTOC *) malloc( buflen );
+    if ( toc_p == NULL ) {
+      fprintf( stderr, "Out of memory\n" );
+      goto Exit;
+    }
+    else {
+      CFDataGetBytes( data, range, (unsigned char *) toc_p );
+    }
+
+    /*
+    fprintf( stderr, "Table of contents\n length %d first %d last %d\n",
+           toc_p->length, toc_p->first_session, toc_p->last_session );
+    */
+
+    CFRelease( properties );
+
+  }
+  
+
+ Exit:
+
+  if ( service ) {
+    IOObjectRelease( service );
+  }
+
+  return toc_p;
+
+}
+#endif
+
+#ifdef WIN32
+
+bool ReadCDSector(unsigned int hid, unsigned int tid, unsigned int lun, unsigned long frame, unsigned char *buf, int bufsize)
+{
+       HANDLE hEventSRB;
+       SRB_ExecSCSICmd srb;
+       DWORD dwStatus;
+
+       hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
+       
+       memset(&srb,0,sizeof(SRB_ExecSCSICmd));
+       srb.SRB_Cmd        = SC_EXEC_SCSI_CMD;
+       srb.SRB_HaId       = hid;
+       srb.SRB_Target     = tid;
+       srb.SRB_Lun        = lun;
+       srb.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+       srb.SRB_SenseLen   = SENSE_LEN;
+       srb.SRB_PostProc   = hEventSRB;
+       srb.SRB_BufPointer = buf;
+       srb.SRB_BufLen     = bufsize;
+       srb.SRB_CDBLen     = 10;
+       srb.CDBByte[0]     = SCSI_READ10;
+       srb.CDBByte[2]     = (unsigned char) (frame>>24);
+       srb.CDBByte[3]     = (unsigned char) (frame>>16);
+       srb.CDBByte[4]     = (unsigned char) (frame>>8);
+       srb.CDBByte[5]     = (unsigned char) (frame);
+       srb.CDBByte[7]     = 0;
+       srb.CDBByte[8]     = 1; /* read 1 frames */
+
+       ResetEvent(hEventSRB);
+       dwStatus = SendASPI32Command((SRB *)&srb);
+       if(dwStatus == SS_PENDING) {
+               WaitForSingleObject(hEventSRB, 100000);
+       }
+       CloseHandle(hEventSRB);
+       return (srb.SRB_TargStat == STATUS_GOOD);
+}
+
+int GetCDCapacity(unsigned int hid, unsigned int tid, unsigned int lun)
+{
+       HANDLE hEventSRB;
+       SRB_ExecSCSICmd srb;
+       DWORD dwStatus;
+       unsigned char buf[8];
+
+       hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
+       
+       memset(&buf, 0, sizeof(buf));
+       memset(&srb,0,sizeof(SRB_ExecSCSICmd));
+       srb.SRB_Cmd        = SC_EXEC_SCSI_CMD;
+       srb.SRB_HaId       = hid;
+       srb.SRB_Target     = tid;
+       srb.SRB_Lun        = lun;
+       srb.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
+       srb.SRB_SenseLen   = SENSE_LEN;
+       srb.SRB_PostProc   = hEventSRB;
+       srb.SRB_BufPointer = (unsigned char *)buf;
+       srb.SRB_BufLen     = 8;
+       srb.SRB_CDBLen     = 10;
+       srb.CDBByte[0]     = SCSI_READCDCAP;
+       srb.CDBByte[2]     = 0;
+       srb.CDBByte[3]     = 0;
+       srb.CDBByte[4]     = 0;
+       srb.CDBByte[5]     = 0;
+       srb.CDBByte[8]     = 0;
+
+       ResetEvent(hEventSRB);
+       dwStatus = SendASPI32Command((SRB *)&srb);
+       if(dwStatus == SS_PENDING) {
+               WaitForSingleObject(hEventSRB, 100000);
+       }
+
+       CloseHandle(hEventSRB);
+       return ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]) * ((buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]);
+}
+
+#endif
+
+cdrom_interface::cdrom_interface(char *dev)
+{
+  put("CD");
+  settype(CDLOG);
+  fd = -1; // File descriptor not yet allocated
+
+  if ( dev == NULL )
+    path = NULL;
+  else {
+    path = strdup(dev);
+  }
+  using_file=0;
+}
+
+void
+cdrom_interface::init(void) {
+  BX_DEBUG(("Init $Id: cdrom.cc,v 1.66 2003/12/08 23:49:48 danielg4 Exp $"));
+  BX_INFO(("file = '%s'",path));
+}
+
+cdrom_interface::~cdrom_interface(void)
+{
+#ifdef WIN32
+#else
+       if (fd >= 0)
+               close(fd);
+#endif
+       if (path)
+               free(path);
+       BX_DEBUG(("Exit"));
+}
+
+  bx_bool
+cdrom_interface::insert_cdrom(char *dev)
+{
+  unsigned char buffer[BX_CD_FRAMESIZE];
+  ssize_t ret;
+
+  // Load CD-ROM. Returns false if CD is not ready.
+  if (dev != NULL) path = strdup(dev);
+  BX_INFO (("load cdrom with path=%s", path));
+#ifdef WIN32
+    char drive[256];
+       OSVERSIONINFO osi;
+    if ( (path[1] == ':') && (strlen(path) == 2) )
+    {
+         osi.dwOSVersionInfoSize = sizeof(osi);
+         GetVersionEx(&osi);
+         if(osi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+           // Use direct device access under windows NT/2k
+
+        // With all the backslashes it's hard to see, but to open D: drive 
+        // the name would be: \\.\d:
+        sprintf(drive, "\\\\.\\%s", path);
+        using_file = 0;
+        BX_INFO (("Using direct access for cdrom."));
+        // This trick only works for Win2k and WinNT, so warn the user of that.
+         } else {
+                 BX_INFO(("Using ASPI for cdrom. Drive letters are unused yet."));
+          bUseASPI = TRUE;
+         }
+    }
+    else
+    {
+      strcpy(drive,path);
+      using_file = 1;
+         bUseASPI = FALSE;
+      BX_INFO (("Opening image file as a cd"));
+    }
+       if(bUseASPI) {
+               DWORD d;
+               UINT cdr, cnt, max;
+               UINT i, j, k;
+               SRB_HAInquiry sh;
+               SRB_GDEVBlock sd;
+               if (!hASPI) {
+                 hASPI = LoadLibrary("WNASPI32.DLL");
+               }
+               if(hASPI) {
+            SendASPI32Command      = (DWORD(*)(LPSRB))GetProcAddress( hASPI, "SendASPI32Command" );
+                       GetASPI32DLLVersion    = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32DLLVersion" );
+                       GetASPI32SupportInfo   = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32SupportInfo" );
+//                     BX_INFO(("Using first CDROM.  Please upgrade your ASPI drivers to version 4.01 or later if you wish to specify a cdrom driver."));
+                       
+                       cdr = 0;
+                       bHaveDev = FALSE;
+                       d = GetASPI32SupportInfo();
+                       cnt = LOBYTE(LOWORD(d));
+                       for(i = 0; i < cnt; i++) {
+                               memset(&sh, 0, sizeof(sh));
+                               sh.SRB_Cmd  = SC_HA_INQUIRY;
+                               sh.SRB_HaId = i;
+                               SendASPI32Command((LPSRB)&sh);
+                               if(sh.SRB_Status != SS_COMP)
+                                       continue;
+
+                               max = (int)sh.HA_Unique[3];
+                               for(j = 0; j < max; j++) {
+                                       for(k = 0; k < 8; k++) {
+                                               memset(&sd, 0, sizeof(sd));
+                                               sd.SRB_Cmd    = SC_GET_DEV_TYPE;
+                                               sd.SRB_HaId   = i;
+                                               sd.SRB_Target = j;
+                                               sd.SRB_Lun    = k;
+                                               SendASPI32Command((LPSRB)&sd);
+                                               if(sd.SRB_Status == SS_COMP) {
+                                                       if(sd.SRB_DeviceType == DTYPE_CDROM) {
+                                                               cdr++;
+                                                               if(cdr > cdromCount) {
+                                                                       hid = i;
+                                                                       tid = j;
+                                                                       lun = k;
+                                                                       cdromCount++;
+                                                                       bHaveDev = TRUE;
+                                                               }
+                                                       }
+                                               }
+                                               if(bHaveDev) break;
+                                       }
+                                       if(bHaveDev) break;
+                               }
+
+                       }
+               } else {
+                       BX_PANIC(("Could not load ASPI drivers, so cdrom access will fail"));
+               }
+               fd=1;
+       } else {
+         BX_INFO(("Using direct access for CDROM"));
+      hFile=CreateFile((char *)&drive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); 
+      if (hFile !=(void *)0xFFFFFFFF)
+        fd=1;
+       }
+#elif defined(__APPLE__)
+      if(strcmp(path, "drive") == 0)
+      {
+        mach_port_t masterPort = NULL;
+        io_iterator_t mediaIterator;
+        kern_return_t kernResult;
+        
+        BX_INFO(( "Insert CDROM" )); 
+        
+        kernResult = FindEjectableCDMedia( &mediaIterator, &masterPort );
+        if ( kernResult != KERN_SUCCESS ) {
+          BX_INFO (("Unable to find CDROM"));
+          return false;
+        }
+        
+        kernResult = GetDeviceFilePath( mediaIterator, CDDevicePath, sizeof( CDDevicePath ) );
+        if ( kernResult != KERN_SUCCESS ) {
+          BX_INFO (("Unable to get CDROM device file path" ));
+          return false;
+        }
+       
+        // Here a cdrom was found so see if we can read from it.
+        // At this point a failure will result in panic.
+        if ( strlen( CDDevicePath ) ) {
+          fd = open(CDDevicePath, O_RDONLY);
+        }
+      }
+      else
+      {
+        fd = open(path, O_RDONLY);
+      }
+#else
+      // all platforms except win32
+      fd = open(path, O_RDONLY);
+#endif
+    if (fd < 0) {
+       BX_ERROR(( "open cd failed for %s: %s", path, strerror(errno)));
+       return(false);
+    }
+
+  // I just see if I can read a sector to verify that a
+  // CD is in the drive and readable.
+#ifdef WIN32
+    if(bUseASPI) {
+      return ReadCDSector(hid, tid, lun, 0, buffer, BX_CD_FRAMESIZE);
+    } else {
+      if (!ReadFile(hFile, (void *) buffer, BX_CD_FRAMESIZE, (unsigned long *) &ret, NULL)) {
+         CloseHandle(hFile);
+         fd = -1;
+         BX_DEBUG(( "insert_cdrom: read returns error." ));
+         return(false);
+      }
+    }
+#else
+    // do fstat to determine if it's a file or a device, then set using_file.
+    struct stat stat_buf;
+    ret = fstat (fd, &stat_buf);
+    if (ret) {
+      BX_PANIC (("fstat cdrom file returned error: %s", strerror (errno)));
+    }
+    if (S_ISREG (stat_buf.st_mode)) {
+      using_file = 1;
+      BX_INFO (("Opening image file %s as a cd.", path));
+    } else {
+      using_file = 0;
+      BX_INFO (("Using direct access for cdrom."));
+    }
+
+    ret = read(fd, (char*) &buffer, BX_CD_FRAMESIZE);
+    if (ret < 0) {
+       close(fd);
+       fd = -1;
+       BX_DEBUG(( "insert_cdrom: read returns error: %s", strerror (errno) ));
+       return(false);
+        }
+#endif
+    return(true);
+}
+
+  int
+cdrom_interface::start_cdrom()
+{
+  // Spin up the cdrom drive.
+
+  if (fd >= 0) {
+#if defined(__NetBSD__)
+    if (ioctl (fd, CDIOCSTART) < 0)
+       BX_DEBUG(( "start_cdrom: start returns error: %s", strerror (errno) ));
+    return(true);
+#else
+    BX_INFO(("start_cdrom: your OS is not supported yet."));
+    return(false); // OS not supported yet, return false always.
+#endif
+    }
+  return(false);
+}
+
+  void
+cdrom_interface::eject_cdrom()
+{
+  // Logically eject the CD.  I suppose we could stick in
+  // some ioctl() calls to really eject the CD as well.
+
+  if (fd >= 0) {
+#if (defined(__OpenBSD__) || defined(__FreeBSD__))
+    (void) ioctl (fd, CDIOCALLOW);
+    if (ioctl (fd, CDIOCEJECT) < 0)
+         BX_DEBUG(( "eject_cdrom: eject returns error." ));
+#endif
+
+#ifdef WIN32
+if (using_file == 0)
+{
+       if(bUseASPI) {
+       } else {
+               DWORD lpBytesReturned;
+               DeviceIoControl(hFile, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &lpBytesReturned, NULL);
+       }
+}
+#else // WIN32
+
+#if __linux__
+  if (!using_file)
+    ioctl (fd, CDROMEJECT, NULL);
+#endif
+
+    close(fd);
+#endif // WIN32
+    fd = -1;
+    }
+}
+
+
+  bx_bool
+cdrom_interface::read_toc(uint8* buf, int* length, bx_bool msf, int start_track)
+{
+  // Read CD TOC. Returns false if start track is out of bounds.
+
+  if (fd < 0) {
+    BX_PANIC(("cdrom: read_toc: file not open."));
+    }
+
+#if defined(WIN32)
+  if (1) { // This is a hack and works okay if there's one rom track only
+#else
+  if (using_file) {
+#endif
+    // From atapi specs : start track can be 0-63, AA
+    if ((start_track > 1) && (start_track != 0xaa)) 
+      return false;
+
+    buf[2] = 1;
+    buf[3] = 1;
+
+    int len = 4;
+    if (start_track <= 1) {
+      buf[len++] = 0; // Reserved
+      buf[len++] = 0x14; // ADR, control
+      buf[len++] = 1; // Track number
+      buf[len++] = 0; // Reserved
+
+      // Start address
+      if (msf) {
+        buf[len++] = 0; // reserved
+        buf[len++] = 0; // minute
+        buf[len++] = 2; // second
+        buf[len++] = 0; // frame
+      } else {
+        buf[len++] = 0;
+        buf[len++] = 0;
+        buf[len++] = 0;
+        buf[len++] = 0; // logical sector 0
+      }
+    }
+
+    // Lead out track
+    buf[len++] = 0; // Reserved
+    buf[len++] = 0x16; // ADR, control
+    buf[len++] = 0xaa; // Track number
+    buf[len++] = 0; // Reserved
+
+    uint32 blocks = capacity();
+
+    // Start address
+    if (msf) {
+      buf[len++] = 0; // reserved
+      buf[len++] = (uint8)(((blocks + 150) / 75) / 60); // minute
+      buf[len++] = (uint8)(((blocks + 150) / 75) % 60); // second
+      buf[len++] = (uint8)((blocks + 150) % 75); // frame;
+    } else {
+      buf[len++] = (blocks >> 24) & 0xff;
+      buf[len++] = (blocks >> 16) & 0xff;
+      buf[len++] = (blocks >> 8) & 0xff;
+      buf[len++] = (blocks >> 0) & 0xff;
+    }
+
+    buf[0] = ((len-2) >> 8) & 0xff;
+    buf[1] = (len-2) & 0xff;
+
+    *length = len;
+
+    return true;
+  }
+  // all these implementations below are the platform-dependent code required
+  // to read the TOC from a physical cdrom.
+#ifdef WIN32
+  {
+/*     #define IOCTL_CDROM_BASE                 FILE_DEVICE_CD_ROM
+     #define IOCTL_CDROM_READ_TOC         CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+     unsigned long iBytesReturned;
+     DeviceIoControl(hFile, IOCTL_CDROM_READ_TOC, NULL, 0, NULL, 0, &iBytesReturned, NULL);       */
+    BX_ERROR (("WARNING: read_toc is not implemented, just returning length=1"));
+    *length = 1;
+    return true;
+  }
+#elif __linux__ || defined(__sun)
+  {
+  struct cdrom_tochdr tochdr;
+  if (ioctl(fd, CDROMREADTOCHDR, &tochdr))
+    BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
+
+  if ((start_track > tochdr.cdth_trk1) && (start_track != 0xaa))
+    return false;
+
+  buf[2] = tochdr.cdth_trk0;
+  buf[3] = tochdr.cdth_trk1;
+
+  if (start_track < tochdr.cdth_trk0)
+    start_track = tochdr.cdth_trk0;
+
+  int len = 4;
+  for (int i = start_track; i <= tochdr.cdth_trk1; i++) {
+    struct cdrom_tocentry tocentry;
+    tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
+    tocentry.cdte_track = i;
+    if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
+      BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
+    buf[len++] = 0; // Reserved
+    buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
+    buf[len++] = i; // Track number
+    buf[len++] = 0; // Reserved
+
+    // Start address
+    if (msf) {
+      buf[len++] = 0; // reserved
+      buf[len++] = tocentry.cdte_addr.msf.minute;
+      buf[len++] = tocentry.cdte_addr.msf.second;
+      buf[len++] = tocentry.cdte_addr.msf.frame;
+    } else {
+      buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
+      buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
+      buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
+      buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
+    }
+  }
+
+  // Lead out track
+  struct cdrom_tocentry tocentry;
+  tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
+#ifdef CDROM_LEADOUT
+  tocentry.cdte_track = CDROM_LEADOUT;
+#else
+  tocentry.cdte_track = 0xaa;
+#endif
+  if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
+    BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
+  buf[len++] = 0; // Reserved
+  buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
+  buf[len++] = 0xaa; // Track number
+  buf[len++] = 0; // Reserved
+
+  // Start address
+  if (msf) {
+    buf[len++] = 0; // reserved
+    buf[len++] = tocentry.cdte_addr.msf.minute;
+    buf[len++] = tocentry.cdte_addr.msf.second;
+    buf[len++] = tocentry.cdte_addr.msf.frame;
+  } else {
+    buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
+    buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
+    buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
+    buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
+  }
+
+  buf[0] = ((len-2) >> 8) & 0xff;
+  buf[1] = (len-2) & 0xff;
+
+  *length = len;
+
+  return true;
+  }
+#elif (defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__))
+  {
+  struct ioc_toc_header h;
+  struct ioc_read_toc_entry t;
+
+  if (ioctl (fd, CDIOREADTOCHEADER, &h) < 0)
+    BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
+
+  if ((start_track > h.ending_track) && (start_track != 0xaa))
+    return false;
+
+  buf[2] = h.starting_track;
+  buf[3] = h.ending_track;
+
+  if (start_track < h.starting_track)
+    start_track = h.starting_track;
+
+  int len = 4;
+  for (int i = start_track; i <= h.ending_track; i++) {
+    struct cd_toc_entry tocentry;
+    t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
+    t.starting_track = i;
+    t.data_len = sizeof(tocentry);
+    t.data = &tocentry;
+
+    if (ioctl (fd, CDIOREADTOCENTRYS, &t) < 0)
+      BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
+
+    buf[len++] = 0; // Reserved
+    buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
+    buf[len++] = i; // Track number
+    buf[len++] = 0; // Reserved
+
+    // Start address
+    if (msf) {
+      buf[len++] = 0; // reserved
+      buf[len++] = tocentry.addr.msf.minute;
+      buf[len++] = tocentry.addr.msf.second;
+      buf[len++] = tocentry.addr.msf.frame;
+    } else {
+      buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
+      buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
+      buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
+      buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
+    }
+  }
+
+  // Lead out track
+  struct cd_toc_entry tocentry;
+  t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
+  t.starting_track = 0xaa;
+  t.data_len = sizeof(tocentry);
+  t.data = &tocentry;
+
+  if (ioctl (fd, CDIOREADTOCENTRYS, &t) < 0)
+    BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
+
+  buf[len++] = 0; // Reserved
+  buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
+  buf[len++] = 0xaa; // Track number
+  buf[len++] = 0; // Reserved
+
+  // Start address
+  if (msf) {
+    buf[len++] = 0; // reserved
+    buf[len++] = tocentry.addr.msf.minute;
+    buf[len++] = tocentry.addr.msf.second;
+    buf[len++] = tocentry.addr.msf.frame;
+  } else {
+    buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
+    buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
+    buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
+    buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
+  }
+
+  buf[0] = ((len-2) >> 8) & 0xff;
+  buf[1] = (len-2) & 0xff;
+
+  *length = len;
+
+  return true;
+  }
+#elif defined(__APPLE__)
+  // Read CD TOC. Returns false if start track is out of bounds.
+
+#if 1
+  {
+  struct _CDTOC * toc = ReadTOC( CDDevicePath );
+  
+  if ((start_track > toc->last_session) && (start_track != 0xaa))
+    return false;
+
+  buf[2] = toc->first_session;
+  buf[3] = toc->last_session;
+
+  if (start_track < toc->first_session)
+    start_track = toc->first_session;
+
+  int len = 4;
+  for (int i = start_track; i <= toc->last_session; i++) {
+    buf[len++] = 0; // Reserved
+    buf[len++] = toc->trackdesc[i].ctrl_adr ; // ADR, control
+    buf[len++] = i; // Track number
+    buf[len++] = 0; // Reserved
+
+    // Start address
+    if (msf) {
+      buf[len++] = 0; // reserved
+      buf[len++] = toc->trackdesc[i].address.minute;
+      buf[len++] = toc->trackdesc[i].address.second;
+      buf[len++] = toc->trackdesc[i].address.frame;
+    } else {
+      unsigned lba = (unsigned)(MSF_TO_LBA(toc->trackdesc[i].address));
+      buf[len++] = (lba >> 24) & 0xff;
+      buf[len++] = (lba >> 16) & 0xff;
+      buf[len++] = (lba >> 8) & 0xff;
+      buf[len++] = (lba >> 0) & 0xff;
+    }
+  }
+
+  // Lead out track
+  buf[len++] = 0; // Reserved
+  buf[len++] = 0x16; // ADR, control
+  buf[len++] = 0xaa; // Track number
+  buf[len++] = 0; // Reserved
+
+  uint32 blocks = capacity();
+
+  // Start address
+  if (msf) {
+    buf[len++] = 0; // reserved
+    buf[len++] = (uint8)(((blocks + 150) / 75) / 60); // minute
+    buf[len++] = (uint8)(((blocks + 150) / 75) % 60); // second
+    buf[len++] = (uint8)((blocks + 150) % 75); // frame;
+  } else {
+    buf[len++] = (blocks >> 24) & 0xff;
+    buf[len++] = (blocks >> 16) & 0xff;
+    buf[len++] = (blocks >> 8) & 0xff;
+    buf[len++] = (blocks >> 0) & 0xff;
+  }
+
+  buf[0] = ((len-2) >> 8) & 0xff;
+  buf[1] = (len-2) & 0xff;
+
+  *length = len;
+
+  return true;
+//  BX_INFO(( "Read TOC - Not Implemented" ));
+//  return false;
+  }
+#else
+  BX_INFO(( "Read TOC - Not Implemented" ));
+  return false;
+#endif
+#else
+  BX_INFO(("read_toc: your OS is not supported yet."));
+  return(false); // OS not supported yet, return false always.
+#endif
+}
+
+
+  uint32
+cdrom_interface::capacity()
+{
+  // Return CD-ROM capacity.  I believe you want to return
+  // the number of blocks of capacity the actual media has.
+
+#if !defined WIN32
+  // win32 has its own way of doing this
+  if (using_file) {
+    // return length of the image file
+    struct stat stat_buf;
+    int ret = fstat (fd, &stat_buf);
+    if (ret) {
+       BX_PANIC (("fstat on cdrom image returned err: %s", strerror(errno)));
+    }
+    BX_INFO (("cdrom size is %lld bytes", stat_buf.st_size));
+    if ((stat_buf.st_size % 2048) != 0)  {
+      BX_ERROR (("expected cdrom image to be a multiple of 2048 bytes"));
+    }
+    return stat_buf.st_size / 2048;
+  }
+#endif
+
+#ifdef __BEOS__
+       return GetNumDeviceBlocks(fd, BX_CD_FRAMESIZE);
+#elif defined(__sun)
+  {
+    struct stat buf = {0};
+
+    if (fd < 0) {
+      BX_PANIC(("cdrom: capacity: file not open."));
+    } 
+    
+    if( fstat(fd, &buf) != 0 )
+      BX_PANIC(("cdrom: capacity: stat() failed."));
+  
+    return(buf.st_size);
+  }
+#elif (defined(__NetBSD__) || defined(__OpenBSD__))
+  {
+  // We just read the disklabel, imagine that...
+  struct disklabel lp;
+
+  if (fd < 0)
+    BX_PANIC(("cdrom: capacity: file not open."));
+
+  if (ioctl(fd, DIOCGDINFO, &lp) < 0)
+    BX_PANIC(("cdrom: ioctl(DIOCGDINFO) failed"));
+
+  BX_DEBUG(( "capacity: %u", lp.d_secperunit ));
+  return(lp.d_secperunit);
+  }
+#elif defined(__linux__)
+  {
+  // Read the TOC to get the data size, since BLKGETSIZE doesn't work on
+  // non-ATAPI drives.  This is based on Keith Jones code below.
+  // <splite@purdue.edu> 21 June 2001
+
+  int i, dtrk_lba, num_sectors;
+  int dtrk = 0;
+  struct cdrom_tochdr td;
+  struct cdrom_tocentry te;
+
+  if (fd < 0)
+    BX_PANIC(("cdrom: capacity: file not open."));
+
+  if (ioctl(fd, CDROMREADTOCHDR, &td) < 0)
+    BX_PANIC(("cdrom: ioctl(CDROMREADTOCHDR) failed"));
+
+  num_sectors = -1;
+  dtrk_lba = -1;
+
+  for (i = td.cdth_trk0; i <= td.cdth_trk1; i++) {
+    te.cdte_track = i;
+    te.cdte_format = CDROM_LBA;
+    if (ioctl(fd, CDROMREADTOCENTRY, &te) < 0)
+      BX_PANIC(("cdrom: ioctl(CDROMREADTOCENTRY) failed"));
+
+    if (dtrk_lba != -1) {
+      num_sectors = te.cdte_addr.lba - dtrk_lba;
+      break;
+    }
+    if (te.cdte_ctrl & CDROM_DATA_TRACK) {
+      dtrk = i;
+      dtrk_lba = te.cdte_addr.lba;
+    }
+  }
+
+  if (num_sectors < 0) {
+    if (dtrk_lba != -1) {
+      te.cdte_track = CDROM_LEADOUT;
+      te.cdte_format = CDROM_LBA;
+      if (ioctl(fd, CDROMREADTOCENTRY, &te) < 0)
+        BX_PANIC(("cdrom: ioctl(CDROMREADTOCENTRY) failed"));
+      num_sectors = te.cdte_addr.lba - dtrk_lba;
+    } else
+      BX_PANIC(("cdrom: no data track found"));
+  }
+
+  BX_INFO(("cdrom: Data track %d, length %d", dtrk, num_sectors));
+
+  return(num_sectors);
+
+  }
+#elif defined(__FreeBSD__)
+  {
+  // Read the TOC to get the size of the data track.
+  // Keith Jones <freebsd.dev@blueyonder.co.uk>, 16 January 2000
+
+#define MAX_TRACKS 100
+
+  int i, num_tracks, num_sectors;
+  struct ioc_toc_header td;
+  struct ioc_read_toc_entry rte;
+  struct cd_toc_entry toc_buffer[MAX_TRACKS + 1];
+
+  if (fd < 0)
+    BX_PANIC(("cdrom: capacity: file not open."));
+
+  if (ioctl(fd, CDIOREADTOCHEADER, &td) < 0)
+    BX_PANIC(("cdrom: ioctl(CDIOREADTOCHEADER) failed"));
+
+  num_tracks = (td.ending_track - td.starting_track) + 1;
+  if (num_tracks > MAX_TRACKS)
+    BX_PANIC(("cdrom: TOC is too large"));
+
+  rte.address_format = CD_LBA_FORMAT;
+  rte.starting_track = td.starting_track;
+  rte.data_len = (num_tracks + 1) * sizeof(struct cd_toc_entry);
+  rte.data = toc_buffer;
+  if (ioctl(fd, CDIOREADTOCENTRYS, &rte) < 0)
+    BX_PANIC(("cdrom: ioctl(CDIOREADTOCENTRYS) failed"));
+
+  num_sectors = -1;
+  for (i = 0; i < num_tracks; i++) {
+    if (rte.data[i].control & 4) {     /* data track */
+      num_sectors = ntohl(rte.data[i + 1].addr.lba)
+          - ntohl(rte.data[i].addr.lba);
+      BX_INFO(( "cdrom: Data track %d, length %d",
+        rte.data[i].track, num_sectors));
+      break;
+      }
+    }
+
+  if (num_sectors < 0)
+    BX_PANIC(("cdrom: no data track found"));
+
+  return(num_sectors);
+
+  }
+#elif defined WIN32
+  {
+         if(bUseASPI) {
+                 return (GetCDCapacity(hid, tid, lun) / 2352);
+         } else if(using_file) {
+           ULARGE_INTEGER FileSize;
+           FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart);
+               return (FileSize.QuadPart / 2048);
+         } else {  /* direct device access */
+           DWORD SectorsPerCluster;
+           DWORD TotalNumOfClusters;
+           GetDiskFreeSpace( path, &SectorsPerCluster, NULL, NULL, &TotalNumOfClusters);
+               return (TotalNumOfClusters * SectorsPerCluster);
+         }
+  }
+#elif defined __APPLE__
+// Find the size of the first data track on the cd.  This has produced
+// the same results as the linux version on every cd I have tried, about
+// 5.  The differences here seem to be that the entries in the TOC when
+// retrieved from the IOKit interface appear in a reversed order when
+// compared with the linux READTOCENTRY ioctl.
+  {
+  // Return CD-ROM capacity.  I believe you want to return
+  // the number of bytes of capacity the actual media has.
+
+  BX_INFO(( "Capacity" ));
+
+  struct _CDTOC * toc = ReadTOC( CDDevicePath );
+
+  if ( toc == NULL ) {
+    BX_PANIC(( "capacity: Failed to read toc" ));
+  }
+
+  size_t toc_entries = ( toc->length - 2 ) / sizeof( struct _CDTOC_Desc );
+  
+  BX_DEBUG(( "reading %d toc entries\n", toc_entries ));
+
+  int start_sector = -1;
+  int data_track = -1;
+
+  // Iterate through the list backward. Pick the first data track and
+  // get the address of the immediately previous (or following depending
+  // on how you look at it).  The difference in the sector numbers
+  // is returned as the sized of the data track.
+  for ( int i=toc_entries - 1; i>=0; i-- ) {
+
+    BX_DEBUG(( "session %d ctl_adr %d tno %d point %d lba %d z %d p lba %d\n",
+             (int)toc->trackdesc[i].session,
+             (int)toc->trackdesc[i].ctrl_adr,
+             (int)toc->trackdesc[i].tno,
+             (int)toc->trackdesc[i].point,
+             MSF_TO_LBA( toc->trackdesc[i].address ),
+             (int)toc->trackdesc[i].zero,
+             MSF_TO_LBA(toc->trackdesc[i].p )));
+
+    if ( start_sector != -1 ) {
+
+      start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
+      break;
+
+    }
+
+    if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 ) continue;
+
+    if ( toc->trackdesc[i].ctrl_adr & 0x04 ) {
+
+      data_track = toc->trackdesc[i].point;
+
+      start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
+
+    }
+      
+  }  
+
+  free( toc );
+
+  if ( start_sector == -1 ) {
+    start_sector = 0;
+  }
+
+  BX_INFO(("first data track %d data size is %d", data_track, start_sector));
+
+  return start_sector;
+  }
+#else
+  BX_ERROR(( "capacity: your OS is not supported yet." ));
+  return(0);
+#endif
+}
+
+  void BX_CPP_AttrRegparmN(2)
+cdrom_interface::read_block(uint8* buf, int lba)
+{
+  // Read a single block from the CD
+
+#ifdef WIN32
+  LARGE_INTEGER pos;
+#else
+  off_t pos;
+#endif
+  ssize_t n;
+
+#ifdef WIN32
+  if(bUseASPI) {
+         ReadCDSector(hid, tid, lun, lba, buf, BX_CD_FRAMESIZE);
+         n = BX_CD_FRAMESIZE;
+  } else {
+    pos.QuadPart = (LONGLONG)lba*BX_CD_FRAMESIZE;
+    pos.LowPart = SetFilePointer(hFile, pos.LowPart, &pos.HighPart, SEEK_SET);
+    if ((pos.LowPart == 0xffffffff) && (GetLastError() != NO_ERROR)) {
+      BX_PANIC(("cdrom: read_block: SetFilePointer returned error."));
+       }
+       ReadFile(hFile, (void *) buf, BX_CD_FRAMESIZE, (unsigned long *) &n, NULL);
+  }
+#elif defined(__APPLE__)
+#define CD_SEEK_DISTANCE kCDSectorSizeWhole
+  if(using_file)
+  {
+    pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
+    if (pos < 0) {
+      BX_PANIC(("cdrom: read_block: lseek returned error."));
+  }
+  n = read(fd, buf, BX_CD_FRAMESIZE);
+  }
+  else
+  {
+    // This seek will leave us 16 bytes from the start of the data
+    // hence the magic number. 
+    pos = lseek(fd, lba*CD_SEEK_DISTANCE + 16, SEEK_SET);
+    if (pos < 0) {
+      BX_PANIC(("cdrom: read_block: lseek returned error."));
+    }
+    n = read(fd, buf, CD_FRAMESIZE);
+  }
+#else
+  pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
+  if (pos < 0) {
+    BX_PANIC(("cdrom: read_block: lseek returned error."));
+  }
+  n = read(fd, (char*) buf, BX_CD_FRAMESIZE);
+#endif
+
+  if (n != BX_CD_FRAMESIZE) {
+    BX_PANIC(("cdrom: read_block: read returned %d",
+      (int) n));
+    }
+}
+
+#endif /* if BX_SUPPORT_CDROM */
diff --git a/tools/ioemu/iodev/cdrom.h b/tools/ioemu/iodev/cdrom.h
new file mode 100644 (file)
index 0000000..29fdfaf
--- /dev/null
@@ -0,0 +1,67 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cdrom.h,v 1.13 2003/08/19 00:37:03 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Header file for low-level OS specific CDROM emulation
+
+
+class cdrom_interface : public logfunctions {
+public:
+  cdrom_interface(char *dev);
+  ~cdrom_interface(void);
+  void init(void);
+
+  // Load CD-ROM. Returns false if CD is not ready.
+  bx_bool insert_cdrom(char *dev = NULL);
+
+  // Logically eject the CD.
+  void eject_cdrom();
+
+  // Read CD TOC. Returns false if start track is out of bounds.
+  bx_bool read_toc(uint8* buf, int* length, bx_bool msf, int start_track);
+
+  // Return CD-ROM capacity (in 2048 byte frames)
+  uint32 capacity();
+
+  // Read a single block from the CD
+  void read_block(uint8* buf, int lba) BX_CPP_AttrRegparmN(2);
+
+  // Start (spin up) the CD.
+  int start_cdrom();
+
+private:
+  int fd;
+  char *path;
+
+  int using_file;
+#ifdef WIN32
+  HANDLE hFile;
+  int hid;
+  int tid;
+  int lun;
+#endif
+  };
+
diff --git a/tools/ioemu/iodev/cdrom_beos.h b/tools/ioemu/iodev/cdrom_beos.h
new file mode 100644 (file)
index 0000000..8a22d5c
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef CDROM_BEOS_H
+#define CDROM_BEOS_H
+
+#include <stddef.h> //for off_t
+
+off_t GetNumDeviceBlocks(int fd, int block_size);
+int GetLogicalBlockSize(int fd);
+int GetDeviceBlockSize(int fd);
+
+#endif
diff --git a/tools/ioemu/iodev/cmos.cc b/tools/ioemu/iodev/cmos.cc
new file mode 100644 (file)
index 0000000..fbf3144
--- /dev/null
@@ -0,0 +1,824 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cmos.cc,v 1.44 2003/12/27 13:43:41 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theCmosDevice->
+
+bx_cmos_c *theCmosDevice = NULL;
+
+// CMOS register definitions from Ralf Brown's interrupt list v6.1, in a file
+// called cmos.lst.  In cases where there are multiple uses for a given
+// register in the interrupt list, I only listed the purpose that Bochs
+// actually uses it for, but I wrote "alternatives" next to it.
+#define  REG_SEC                     0x00
+#define  REG_SEC_ALARM               0x01
+#define  REG_MIN                     0x02
+#define  REG_MIN_ALARM               0x03
+#define  REG_HOUR                    0x04
+#define  REG_HOUR_ALARM              0x05
+#define  REG_WEEK_DAY                0x06
+#define  REG_MONTH_DAY               0x07
+#define  REG_MONTH                   0x08
+#define  REG_YEAR                    0x09
+#define  REG_STAT_A                  0x0a
+#define  REG_STAT_B                  0x0b
+#define  REG_STAT_C                  0x0c
+#define  REG_STAT_D                  0x0d
+#define  REG_DIAGNOSTIC_STATUS       0x0e  /* alternatives */
+#define  REG_SHUTDOWN_STATUS         0x0f
+#define  REG_EQUIPMENT_BYTE          0x14
+#define  REG_CSUM_HIGH               0x2e
+#define  REG_CSUM_LOW                0x2f
+#define  REG_IBM_CENTURY_BYTE        0x32  /* alternatives */
+#define  REG_IBM_PS2_CENTURY_BYTE    0x37  /* alternatives */
+
+// Bochs CMOS map (to be completed)
+//
+// Idx  Len   Description
+// 0x15   2   Base memory in 1k
+// 0x17   2   Memory size above 1M in 1k
+// 0x30   2   Memory size above 1M in 1k
+// 0x34   2   Memory size above 16M in 64k
+//
+
+// check that BX_NUM_CMOS_REGS is 64 or 128
+#if (BX_NUM_CMOS_REGS == 64)
+#elif (BX_NUM_CMOS_REGS == 128)
+#else
+#error "Invalid BX_NUM_CMOS_REGS value in config.h"
+#endif
+
+
+  int
+libcmos_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theCmosDevice = new bx_cmos_c ();
+  bx_devices.pluginCmosDevice = theCmosDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theCmosDevice, BX_PLUGIN_CMOS);
+  return(0); // Success
+}
+
+  void
+libcmos_LTX_plugin_fini(void)
+{
+}
+
+bx_cmos_c::bx_cmos_c(void)
+{
+  put("CMOS");
+  settype(CMOSLOG);
+
+  unsigned i;
+  for (i=0; i<BX_NUM_CMOS_REGS; i++)
+    s.reg[i] = 0;
+  s.periodic_timer_index = BX_NULL_TIMER_HANDLE;
+  s.one_second_timer_index = BX_NULL_TIMER_HANDLE;
+  s.uip_timer_index = BX_NULL_TIMER_HANDLE;
+}
+
+bx_cmos_c::~bx_cmos_c(void)
+{
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_cmos_c::init(void)
+{
+  BX_DEBUG(("Init $Id: cmos.cc,v 1.44 2003/12/27 13:43:41 vruppert Exp $"));
+  // CMOS RAM & RTC
+
+  DEV_register_ioread_handler(this, read_handler, 0x0070, "CMOS RAM", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0071, "CMOS RAM", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0070, "CMOS RAM", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0071, "CMOS RAM", 1);
+  DEV_register_irq(8, "CMOS RTC"); 
+  if (BX_CMOS_THIS s.periodic_timer_index == BX_NULL_TIMER_HANDLE) {
+    BX_CMOS_THIS s.periodic_timer_index =
+      DEV_register_timer(this, periodic_timer_handler,
+        1000000, 1,0, "cmos"); // continuous, not-active
+  }
+  if (BX_CMOS_THIS s.one_second_timer_index == BX_NULL_TIMER_HANDLE) {
+    BX_CMOS_THIS s.one_second_timer_index =
+      DEV_register_timer(this, one_second_timer_handler,
+        1000000, 1,0, "cmos"); // continuous, not-active
+  }
+  if (BX_CMOS_THIS s.uip_timer_index == BX_NULL_TIMER_HANDLE) {
+    BX_CMOS_THIS s.uip_timer_index =
+      DEV_register_timer(this, uip_timer_handler,
+        244, 0, 0, "cmos"); // one-shot, not-active
+  }
+
+#if BX_USE_SPECIFIED_TIME0 != 0
+  // ??? this will not be correct for using an image file.
+  // perhaps take values in CMOS and work backwards to find
+  // s.timeval from values read in.
+  BX_CMOS_THIS s.timeval = BX_USE_SPECIFIED_TIME0;
+
+#else // BX_USE_SPECIFIED_TIME0 != 0
+
+  // localtime
+  if (bx_options.clock.Otime0->get () == BX_CLOCK_TIME0_LOCAL) {
+       BX_INFO(("Using local time for initial clock"));
+       BX_CMOS_THIS s.timeval = time(NULL);
+  }
+  // utc
+  else if (bx_options.clock.Otime0->get () == BX_CLOCK_TIME0_UTC) {
+       bx_bool utc_ok = 0;
+
+       BX_INFO(("Using utc time for initial clock"));
+       
+       BX_CMOS_THIS s.timeval = time(NULL);
+
+#if BX_HAVE_GMTIME
+#if BX_HAVE_MKTIME
+       struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
+       utc_holder->tm_isdst = -1;
+       utc_ok = 1;
+       BX_CMOS_THIS s.timeval = mktime(utc_holder);
+#elif BX_HAVE_TIMELOCAL
+       struct tm *utc_holder = gmtime(&BX_CMOS_THIS s.timeval);
+       utc_holder->tm_isdst = 0;       // XXX Is this correct???
+       utc_ok = 1;
+       BX_CMOS_THIS s.timeval = timelocal(utc_holder);
+#endif //BX_HAVE_MKTIME
+#endif //BX_HAVE_GMTIME
+
+       if (!utc_ok) {
+           BX_ERROR(("UTC time is not supported on your platform. Using current time(NULL)"));
+       }
+  }
+  else {
+       BX_INFO(("Using specified time for initial clock"));
+       BX_CMOS_THIS s.timeval = bx_options.clock.Otime0->get ();
+  }
+#endif // BX_USE_SPECIFIED_TIME0 != 0
+
+  char *tmptime;
+  while( (tmptime =  strdup(ctime(&(BX_CMOS_THIS s.timeval)))) == NULL) {
+    BX_PANIC(("Out of memory."));
+  }
+  tmptime[strlen(tmptime)-1]='\0';
+
+  BX_INFO(("Setting initial clock to: %s (time0=%u)", tmptime, (Bit32u)BX_CMOS_THIS s.timeval));
+
+  update_clock();
+  BX_CMOS_THIS s.timeval_change = 0;
+
+  // load CMOS from image file if requested.
+  if (bx_options.cmos.OcmosImage->get ()) {
+    // CMOS image file requested
+    int fd, ret;
+    struct stat stat_buf;
+
+    fd = open(bx_options.cmos.Opath->getptr (), O_RDONLY
+#ifdef O_BINARY
+       | O_BINARY
+#endif
+        );
+    if (fd < 0) {
+      BX_PANIC(("trying to open cmos image file '%s'",
+     bx_options.cmos.Opath->getptr ()));
+      }
+    ret = fstat(fd, &stat_buf);
+    if (ret) {
+      BX_PANIC(("CMOS: could not fstat() image file."));
+      }
+    if (stat_buf.st_size != BX_NUM_CMOS_REGS) {
+      BX_PANIC(("CMOS: image file not same size as BX_NUM_CMOS_REGS."));
+      }
+
+    ret = ::read(fd, (bx_ptr_t) BX_CMOS_THIS s.reg, BX_NUM_CMOS_REGS);
+    if (ret != BX_NUM_CMOS_REGS) {
+      BX_PANIC(("CMOS: error reading cmos file."));
+      }
+    close(fd);
+    BX_INFO(("successfuly read from image file '%s'.",
+      bx_options.cmos.Opath->getptr ()));
+    }
+  else {
+    // CMOS values generated
+    BX_CMOS_THIS s.reg[REG_STAT_A] = 0x26;
+    BX_CMOS_THIS s.reg[REG_STAT_B] = 0x02;
+    BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
+    BX_CMOS_THIS s.reg[REG_STAT_D] = 0x80;
+#if BX_SUPPORT_FPU == 1
+    BX_CMOS_THIS s.reg[REG_EQUIPMENT_BYTE] |= 0x02;
+#endif
+    }
+}
+
+  void
+bx_cmos_c::reset(unsigned type)
+{
+  BX_CMOS_THIS s.cmos_mem_address = 0;
+
+  // RESET affects the following registers:
+  //  CRA: no effects
+  //  CRB: bits 4,5,6 forced to 0
+  //  CRC: bits 4,5,6,7 forced to 0
+  //  CRD: no effects
+  BX_CMOS_THIS s.reg[REG_STAT_B] &= 0x8f;
+  BX_CMOS_THIS s.reg[REG_STAT_C] = 0;
+
+  // One second timer for updating clock & alarm functions
+  bx_pc_system.activate_timer(BX_CMOS_THIS s.one_second_timer_index,
+                         1000000, 1);
+
+  // handle periodic interrupt rate select
+  BX_CMOS_THIS CRA_change();
+}
+
+  void
+bx_cmos_c::CRA_change(void)
+{
+  unsigned nibble;
+
+  // Periodic Interrupt timer
+  nibble = BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f;
+  if (nibble == 0) {
+    // No Periodic Interrupt Rate when 0, deactivate timer
+    bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
+    BX_CMOS_THIS s.periodic_interval_usec = (Bit32u) -1; // max value
+    }
+  else {
+    // values 0001b and 0010b are the same as 1000b and 1001b
+    if (nibble <= 2)
+      nibble += 7;
+    BX_CMOS_THIS s.periodic_interval_usec = (unsigned) (1000000.0L /
+     (32768.0L / (1 << (nibble - 1))));
+
+    // if Periodic Interrupt Enable bit set, activate timer
+    if ( BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40 )
+      bx_pc_system.activate_timer(BX_CMOS_THIS s.periodic_timer_index,
+     BX_CMOS_THIS s.periodic_interval_usec, 1);
+    else
+      bx_pc_system.deactivate_timer(BX_CMOS_THIS s.periodic_timer_index);
+    }
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_cmos_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_CMOS_SMF
+  bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+  Bit32u
+bx_cmos_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif
+  Bit8u ret8;
+
+  if (bx_dbg.cmos)
+    BX_INFO(("CMOS read of CMOS register 0x%02x",
+      (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+
+
+  switch (address) {
+    case 0x0070:
+      BX_INFO(("read of index port 0x70. returning 0xff"));
+      // Volker says his boxes return 0xff
+      //ret8 = BX_CMOS_THIS s.cmos_mem_address;
+      return(0xff);
+      break;
+    case 0x0071:
+      if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+     BX_PANIC(("unsupported cmos io read, register(0x%02x)!",
+       (unsigned) BX_CMOS_THIS s.cmos_mem_address));
+     }
+
+      ret8 = BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address];
+      // all bits of Register C are cleared after a read occurs.
+      if (BX_CMOS_THIS s.cmos_mem_address == REG_STAT_C) {
+        BX_CMOS_THIS s.reg[REG_STAT_C] = 0x00;
+        DEV_pic_lower_irq(8);
+        }
+      return(ret8);
+      break;
+
+    default:
+      BX_PANIC(("unsupported cmos read, address=0x%04x!",
+     (unsigned) address));
+      return(0);
+      break;
+    }
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_cmos_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_CMOS_SMF
+  bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_cmos_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_CMOS_SMF
+
+  if (bx_dbg.cmos)
+    BX_INFO(("CMOS write to address: 0x%04x = 0x%02x",
+      (unsigned) address, (unsigned) value));
+
+
+  switch (address) {
+    case 0x0070:
+#if (BX_NUM_CMOS_REGS == 64)
+      BX_CMOS_THIS s.cmos_mem_address = value & 0x3F;
+#else
+      BX_CMOS_THIS s.cmos_mem_address = value & 0x7F;
+#endif
+      break;
+
+    case 0x0071:
+      if (BX_CMOS_THIS s.cmos_mem_address >= BX_NUM_CMOS_REGS) {
+     BX_PANIC(("unsupported cmos io write, register(0x%02x) = 0x%02x !",
+       (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+     return;
+     }
+      switch (BX_CMOS_THIS s.cmos_mem_address) {
+     case REG_SEC_ALARM:             // seconds alarm
+     case REG_MIN_ALARM:             // minutes alarm
+     case REG_HOUR_ALARM:            // hours alarm
+       BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+       BX_DEBUG(("alarm time changed to %02x:%02x:%02x", BX_CMOS_THIS s.reg[REG_HOUR_ALARM],
+                 BX_CMOS_THIS s.reg[REG_MIN_ALARM], BX_CMOS_THIS s.reg[REG_SEC_ALARM]));
+       return;
+       break;
+
+     case REG_SEC:                   // seconds
+     case REG_MIN:                   // minutes
+     case REG_HOUR:                  // hours
+     case REG_WEEK_DAY:              // day of the week
+     case REG_MONTH_DAY:             // day of the month
+     case REG_MONTH:                 // month
+     case REG_YEAR:                  // year
+     case REG_IBM_CENTURY_BYTE:      // century
+     case REG_IBM_PS2_CENTURY_BYTE:  // century (PS/2)
+       //BX_INFO(("write reg 0x%02x: value = 0x%02x",
+       //    (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value);
+       BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+       if (BX_CMOS_THIS s.cmos_mem_address == REG_IBM_PS2_CENTURY_BYTE) {
+         BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = value;
+       }
+       if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80) {
+         BX_CMOS_THIS s.timeval_change = 1;
+       } else {
+         update_timeval();
+       }
+       return;
+       break;
+
+     case REG_STAT_A: // Control Register A
+       // bit 7: Update in Progress (read-only)
+       //   1 = signifies time registers will be updated within 244us
+       //   0 = time registers will not occur before 244us
+       //   note: this bit reads 0 when CRB bit 7 is 1
+       // bit 6..4: Divider Chain Control
+       //   000 oscillator disabled
+       //   001 oscillator disabled
+       //   010 Normal operation
+       //   011 TEST
+       //   100 TEST
+       //   101 TEST
+       //   110 Divider Chain RESET
+       //   111 Divider Chain RESET
+       // bit 3..0: Periodic Interrupt Rate Select
+       //   0000 None
+       //   0001 3.90625  ms
+       //   0010 7.8125   ms
+       //   0011 122.070  us
+       //   0100 244.141  us
+       //   0101 488.281  us
+       //   0110 976.562  us
+       //   0111 1.953125 ms
+       //   1000 3.90625  ms
+       //   1001 7.8125   ms
+       //   1010 15.625   ms
+       //   1011 31.25    ms
+       //   1100 62.5     ms
+       //   1101 125      ms
+       //   1110 250      ms
+       //   1111 500      ms
+
+       unsigned dcc;
+       dcc = (value >> 4) & 0x07;
+       if ((dcc & 0x06) == 0x06) {
+         BX_INFO(("CRA: divider chain RESET"));
+       } else if (dcc != 0x02) {
+         BX_PANIC(("CRA: divider chain control 0x%02x", dcc));
+       }
+       BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x80;
+       BX_CMOS_THIS s.reg[REG_STAT_A] |= (value & 0x7f);
+       BX_CMOS_THIS CRA_change();
+       return;
+       break;
+
+     case REG_STAT_B: // Control Register B
+       // bit 0: Daylight Savings Enable
+       //   1 = enable daylight savings
+       //   0 = disable daylight savings
+       // bit 1: 24/12 houre mode
+       //   1 = 24 hour format
+       //   0 = 12 hour format
+       // bit 2: Data Mode
+       //   1 = binary format
+       //   0 = BCD format
+       // bit 3: "square wave enable"
+       //   Not supported and always read as 0
+       // bit 4: Update Ended Interrupt Enable
+       //   1 = enable generation of update ended interrupt
+       //   0 = disable
+       // bit 5: Alarm Interrupt Enable
+       //   1 = enable generation of alarm interrupt
+       //   0 = disable
+       // bit 6: Periodic Interrupt Enable
+       //   1 = enable generation of periodic interrupt
+       //   0 = disable
+       // bit 7: Set mode
+       //   1 = user copy of time is "frozen" allowing time registers
+       //       to be accessed without regard for an occurance of an update
+       //   0 = time updates occur normally
+
+       // can not handle binary or 12-hour mode yet.
+       if (value & 0x04)
+       BX_PANIC(("write status reg B, binary format enabled."));
+       if ( !(value & 0x02) )
+       BX_PANIC(("write status reg B, 12 hour mode enabled."));
+
+       value &= 0xf7; // bit3 always 0
+       // Note: setting bit 7 clears bit 4
+       if (value & 0x80)
+       value &= 0xef;
+
+       unsigned prev_CRB;
+       prev_CRB = BX_CMOS_THIS s.reg[REG_STAT_B];
+       BX_CMOS_THIS s.reg[REG_STAT_B] = value;
+       if ( (prev_CRB & 0x40) != (value & 0x40) ) {
+       // Periodic Interrupt Enabled changed
+       if (prev_CRB & 0x40) {
+         // transition from 1 to 0, deactivate timer
+         bx_pc_system.deactivate_timer(
+           BX_CMOS_THIS s.periodic_timer_index);
+         }
+       else {
+         // transition from 0 to 1
+         // if rate select is not 0, activate timer
+         if ( (BX_CMOS_THIS s.reg[REG_STAT_A] & 0x0f) != 0 ) {
+           bx_pc_system.activate_timer(
+             BX_CMOS_THIS s.periodic_timer_index,
+             BX_CMOS_THIS s.periodic_interval_usec, 1);
+           }
+         }
+       }
+       if ( (prev_CRB >= 0x80) && (value < 0x80) && BX_CMOS_THIS s.timeval_change) {
+         update_timeval();
+         BX_CMOS_THIS s.timeval_change = 0;
+       }
+       return;
+       break;
+
+     case REG_STAT_C: // Control Register C
+     case REG_STAT_D: // Control Register D
+       BX_ERROR(("write to control register 0x%02x (read-only)",
+              BX_CMOS_THIS s.cmos_mem_address));
+       break;
+
+     case REG_DIAGNOSTIC_STATUS:
+       BX_DEBUG(("write register 0x0e: 0x%02x", (unsigned) value));
+       break;
+
+     case REG_SHUTDOWN_STATUS:
+       switch (value) {
+       case 0x00: /* proceed with normal POST (soft reset) */
+         BX_DEBUG(("Reg 0Fh(00): shutdown action = normal POST"));
+         break;
+       case 0x01: /* shutdown after memory size check */
+         BX_DEBUG(("Reg 0Fh(01): request to change shutdown action"
+                        " to shutdown after memory size check"));
+       case 0x02: /* shutdown after successful memory test */
+         BX_DEBUG(("Reg 0Fh(02): request to change shutdown action"
+                        " to shutdown after successful memory test"));
+         break;
+       case 0x03: /* shutdown after failed memory test */
+         BX_DEBUG(("Reg 0Fh(03): request to change shutdown action"
+                        " to shutdown after successful memory test"));
+         break;
+       case 0x04: /* jump to disk bootstrap routine */
+         BX_DEBUG(("Reg 0Fh(04): request to change shutdown action "
+                        "to jump to disk bootstrap routine."));
+         break;
+       case 0x05: /* flush keyboard (issue EOI) and jump via 40h:0067h */
+         BX_DEBUG(("Reg 0Fh(05): request to change shutdown action "
+                        "to flush keyboard (issue EOI) and jump via 40h:0067h."));
+         break;
+       case 0x06:
+         BX_DEBUG(("Reg 0Fh(06): Shutdown after memory test !"));
+         break;
+       case 0x07: /* reset (after failed test in virtual mode) */
+         BX_DEBUG(("Reg 0Fh(07): request to change shutdown action "
+                        "to reset (after failed test in virtual mode)."));
+         break;
+       case 0x08: /* used by POST during protected-mode RAM test (return to POST) */
+         BX_DEBUG(("Reg 0Fh(08): request to change shutdown action "
+                        "to return to POST (used by POST during protected-mode RAM test)."));
+         break;
+       case 0x09: /* return to BIOS extended memory block move
+                  (interrupt 15h, func 87h was in progress) */
+         BX_DEBUG(("Reg 0Fh(09): request to change shutdown action "
+                        "to return to BIOS extended memory block move."));
+         break;
+       case 0x0a: /* jump to DWORD pointer at 40:67 */
+         BX_DEBUG(("Reg 0Fh(0a): request to change shutdown action"
+                        " to jump to DWORD at 40:67"));
+         break;
+       case 0x0b: /* iret to DWORD pointer at 40:67 */
+         BX_DEBUG(("Reg 0Fh(0b): request to change shutdown action"
+                        " to iret to DWORD at 40:67"));
+         break;
+       case 0x0c: /* retf to DWORD pointer at 40:67 */
+         BX_DEBUG(("Reg 0Fh(0c): request to change shutdown action"
+                        " to retf to DWORD at 40:67"));
+         break;
+       default:
+         BX_PANIC(("unsupported cmos io write to reg F, case 0x%02x!",
+           (unsigned) value));
+         break;
+       }
+       break;
+
+     default:
+       BX_DEBUG(("write reg 0x%02x: value = 0x%02x",
+       (unsigned) BX_CMOS_THIS s.cmos_mem_address, (unsigned) value));
+       break;
+     }
+
+      BX_CMOS_THIS s.reg[BX_CMOS_THIS s.cmos_mem_address] = value;
+      break;
+    }
+}
+
+
+  void
+bx_cmos_c::checksum_cmos(void)
+{
+  unsigned i;
+  Bit16u sum;
+
+  sum = 0;
+  for (i=0x10; i<=0x2d; i++) {
+    sum += BX_CMOS_THIS s.reg[i];
+    }
+  BX_CMOS_THIS s.reg[REG_CSUM_HIGH] = (sum >> 8) & 0xff; /* checksum high */
+  BX_CMOS_THIS s.reg[REG_CSUM_LOW] = (sum & 0xff);      /* checksum low */
+}
+
+  void
+bx_cmos_c::periodic_timer_handler(void *this_ptr)
+{
+  bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+  class_ptr->periodic_timer();
+}
+
+  void
+bx_cmos_c::periodic_timer()
+{
+  // if periodic interrupts are enabled, trip IRQ 8, and
+  // update status register C
+  if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x40) {
+    BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xc0; // Interrupt Request, Periodic Int
+    DEV_pic_raise_irq(8);
+    }
+}
+
+  void
+bx_cmos_c::one_second_timer_handler(void *this_ptr)
+{
+  bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+  class_ptr->one_second_timer();
+}
+
+  void
+bx_cmos_c::one_second_timer()
+{
+  // divider chain reset - RTC stopped
+  if ((BX_CMOS_THIS s.reg[REG_STAT_A] & 0x60) == 0x60)
+    return;
+
+  // update internal time/date buffer
+  BX_CMOS_THIS s.timeval++;
+
+  // Dont update CMOS user copy of time/date if CRB bit7 is 1
+  // Nothing else do to
+  if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x80)
+    return;
+
+  BX_CMOS_THIS s.reg[REG_STAT_A] |= 0x80; // set UIP bit
+
+  // UIP timer for updating clock & alarm functions
+  bx_pc_system.activate_timer(BX_CMOS_THIS s.uip_timer_index,
+                         244, 0);
+}
+
+  void
+bx_cmos_c::uip_timer_handler(void *this_ptr)
+{
+  bx_cmos_c *class_ptr = (bx_cmos_c *) this_ptr;
+
+  class_ptr->uip_timer();
+}
+
+  void
+bx_cmos_c::uip_timer()
+{
+  update_clock();
+
+  // if update interrupts are enabled, trip IRQ 8, and
+  // update status register C
+  if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x10) {
+    BX_CMOS_THIS s.reg[REG_STAT_C] |= 0x90; // Interrupt Request, Update Ended
+    DEV_pic_raise_irq(8);
+    }
+
+  // compare CMOS user copy of time/date to alarm time/date here
+  if (BX_CMOS_THIS s.reg[REG_STAT_B] & 0x20) {
+    // Alarm interrupts enabled
+    bx_bool alarm_match = 1;
+    if ( (BX_CMOS_THIS s.reg[REG_SEC_ALARM] & 0xc0) != 0xc0 ) {
+      // seconds alarm not in dont care mode
+      if (BX_CMOS_THIS s.reg[REG_SEC] != BX_CMOS_THIS s.reg[REG_SEC_ALARM])
+     alarm_match = 0;
+      }
+    if ( (BX_CMOS_THIS s.reg[REG_MIN_ALARM] & 0xc0) != 0xc0 ) {
+      // minutes alarm not in dont care mode
+      if (BX_CMOS_THIS s.reg[REG_MIN] != BX_CMOS_THIS s.reg[REG_MIN_ALARM])
+     alarm_match = 0;
+      }
+    if ( (BX_CMOS_THIS s.reg[REG_HOUR_ALARM] & 0xc0) != 0xc0 ) {
+      // hours alarm not in dont care mode
+      if (BX_CMOS_THIS s.reg[REG_HOUR] != BX_CMOS_THIS s.reg[REG_HOUR_ALARM])
+     alarm_match = 0;
+      }
+    if (alarm_match) {
+      BX_CMOS_THIS s.reg[REG_STAT_C] |= 0xa0; // Interrupt Request, Alarm Int
+      DEV_pic_raise_irq(8);
+      }
+    }
+  BX_CMOS_THIS s.reg[REG_STAT_A] &= 0x7f; // clear UIP bit
+}
+
+
+  void
+bx_cmos_c::update_clock()
+{
+  struct tm *time_calendar;
+  unsigned year, month, day, century;
+  Bit8u val_bcd;
+
+  time_calendar = localtime(& BX_CMOS_THIS s.timeval);
+
+  // update seconds
+  val_bcd =
+     ((time_calendar->tm_sec  / 10) << 4) |
+     (time_calendar->tm_sec % 10);
+  BX_CMOS_THIS s.reg[REG_SEC] = val_bcd;
+
+  // update minutes
+  val_bcd =
+     ((time_calendar->tm_min  / 10) << 4) |
+     (time_calendar->tm_min % 10);
+  BX_CMOS_THIS s.reg[REG_MIN] = val_bcd;
+
+  // update hours
+  val_bcd =
+     ((time_calendar->tm_hour  / 10) << 4) |
+     (time_calendar->tm_hour % 10);
+  BX_CMOS_THIS s.reg[REG_HOUR] = val_bcd;
+
+  // update day of the week
+  day = time_calendar->tm_wday + 1; // 0..6 to 1..7
+  BX_CMOS_THIS s.reg[REG_WEEK_DAY] = ((day / 10) << 4) | (day % 10);
+
+  // update day of the month
+  day = time_calendar->tm_mday;
+  BX_CMOS_THIS s.reg[REG_MONTH_DAY] = ((day / 10) << 4) | (day % 10);
+
+  // update month
+  month   = time_calendar->tm_mon + 1;
+  BX_CMOS_THIS s.reg[REG_MONTH] = ((month / 10) << 4) | (month % 10);
+
+  // update year
+  year = time_calendar->tm_year % 100;
+  BX_CMOS_THIS s.reg[REG_YEAR] = ((year  / 10) << 4) | (year % 10);
+
+  // update century
+  century = (time_calendar->tm_year / 100) + 19;
+  BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] = 
+    ((century  / 10) << 4) | (century % 10);
+
+  // Raul Hudea pointed out that some bioses also use reg 0x37 for the 
+  // century byte.  Tony Heller says this is critical in getting WinXP to run.
+  BX_CMOS_THIS s.reg[REG_IBM_PS2_CENTURY_BYTE] = 
+    BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE];
+}
+
+  void
+bx_cmos_c::update_timeval()
+{
+  struct tm time_calendar;
+  Bit8u val_bin;
+
+  // update seconds
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_SEC] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_SEC] & 0x0f);
+  time_calendar.tm_sec = val_bin;
+
+  // update minutes
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_MIN] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_MIN] & 0x0f);
+  time_calendar.tm_min = val_bin;
+
+  // update hours
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_HOUR] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_HOUR] & 0x0f);
+  time_calendar.tm_hour = val_bin;
+
+  // update day of the month
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_MONTH_DAY] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_MONTH_DAY] & 0x0f);
+  time_calendar.tm_mday = val_bin;
+
+  // update month
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_MONTH] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_MONTH] & 0x0f);
+  time_calendar.tm_mon = val_bin - 1;
+
+  // update year
+  val_bin =
+     ((BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_IBM_CENTURY_BYTE] & 0x0f);
+  val_bin = (val_bin - 19) * 100;
+  val_bin +=
+     (((BX_CMOS_THIS s.reg[REG_YEAR] >> 4) * 10) +
+     (BX_CMOS_THIS s.reg[REG_YEAR] & 0x0f));
+  time_calendar.tm_year = val_bin;
+
+  BX_CMOS_THIS s.timeval = mktime(& time_calendar);
+}
diff --git a/tools/ioemu/iodev/cmos.h b/tools/ioemu/iodev/cmos.h
new file mode 100644 (file)
index 0000000..c53907d
--- /dev/null
@@ -0,0 +1,90 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: cmos.h,v 1.9 2003/01/04 00:02:07 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+
+#if BX_USE_CMOS_SMF
+#  define BX_CMOS_SMF  static
+#  define BX_CMOS_THIS theCmosDevice->
+#else
+#  define BX_CMOS_SMF
+#  define BX_CMOS_THIS this->
+#endif
+
+
+class bx_cmos_c : public bx_cmos_stub_c {
+public:
+  bx_cmos_c(void);
+  ~bx_cmos_c(void);
+
+  virtual void init(void);
+  virtual void checksum_cmos(void);
+  virtual void reset(unsigned type);
+
+  virtual Bit32u get_reg(unsigned reg) {
+    return s.reg[reg];
+  }
+  virtual void set_reg(unsigned reg, Bit32u val) {
+    s.reg[reg] = val;
+  }
+  virtual time_t get_timeval() {
+    return s.timeval;
+  }
+
+  struct {
+    int     periodic_timer_index;
+    Bit32u  periodic_interval_usec;
+    int     one_second_timer_index;
+    int     uip_timer_index;
+    time_t  timeval;
+    Bit8u   cmos_mem_address;
+    bx_bool timeval_change;
+
+    Bit8u   reg[BX_NUM_CMOS_REGS];
+    } s;  // state information
+
+private:
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_CMOS_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned len);
+#endif
+
+public:
+  static void periodic_timer_handler(void *);
+  static void one_second_timer_handler(void *);
+  static void uip_timer_handler(void *);
+  BX_CMOS_SMF void periodic_timer(void);
+  BX_CMOS_SMF void one_second_timer(void);
+  BX_CMOS_SMF void uip_timer(void);
+private:
+  BX_CMOS_SMF void update_clock(void);
+  BX_CMOS_SMF void update_timeval(void);
+  BX_CMOS_SMF void CRA_change(void);
+  };
diff --git a/tools/ioemu/iodev/cpu.cc b/tools/ioemu/iodev/cpu.cc
new file mode 100644 (file)
index 0000000..3e82e7f
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Main cpu loop for handling I/O requests coming from a virtual machine
+ * Copyright © 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "bochs.h"
+#include <cpu/cpu.h>
+#ifdef BX_USE_VMX
+#include <sys/ioctl.h>
+/* According to POSIX 1003.1-2001 */
+#include <sys/select.h>
+
+/* According to earlier standards */
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <values.h>
+#endif
+
+#define LOG_THIS BX_CPU_THIS_PTR
+
+#ifdef BX_USE_VMX
+
+//the evtchn fd for polling
+int evtchn_fd = -1;
+//the evtchn port for polling the notification, should be inputed as bochs's parameter
+u16 ioreq_port = 0;
+
+void *shared_page = NULL;
+
+//some functions to handle the io req packet
+
+//get the ioreq packets from share mem
+ioreq_t* bx_cpu_c::__get_ioreq(void)
+{
+       ioreq_t *req;
+       req = &((vcpu_iodata_t *) shared_page)->vp_ioreq;
+       if (req->state == STATE_IOREQ_READY) {
+               req->state = STATE_IOREQ_INPROCESS;
+       } else {
+               BX_INFO(("False I/O requrest ... in-service already: %lx, pvalid: %lx,port: %lx, data: %lx, count: %lx, size: %lx\n", req->state, req->pdata_valid, req->addr, req->u.data, req->count, req->size));
+               req = NULL;
+       }
+
+       return req;
+}
+
+//use poll to get the port notification
+//ioreq_vec--out,the 
+//retval--the number of ioreq packet
+ioreq_t* bx_cpu_c::get_ioreq(void)
+{
+       ioreq_t *req;
+       int rc;
+       u16 buf[2];
+       rc = read(evtchn_fd, buf, 2);
+       if (rc == 2 && buf[0] == ioreq_port){//got only one matched 16bit port index
+               // unmask the wanted port again
+               write(evtchn_fd, &ioreq_port, 2);
+
+               //get the io packet from shared memory
+               return __get_ioreq();
+       }
+
+       //read error or read nothing
+       return NULL;
+}
+
+//send the ioreq to device model
+void bx_cpu_c::dispatch_ioreq(ioreq_t *req)
+{
+       int ret, i;
+
+       if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) {
+               if (req->size != 4) {
+                       // Bochs expects higher bits to be 0
+                       req->u.data &= (1UL << (8 * req->size))-1;
+               }
+       }
+       if (req->port_mm == 0){//port io
+               if(req->dir == IOREQ_READ){//read
+                       if (!req->pdata_valid)
+                               req->u.data = BX_INP(req->addr, req->size);
+                       else {
+                               unsigned long tmp; 
+
+                               for (i = 0; i < req->count; i++) {
+                                       tmp = BX_INP(req->addr, req->size);
+                                       BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (i * req->size), 
+                                                              req->size, &tmp);
+                               }
+                       }
+               } else if(req->dir == IOREQ_WRITE) {
+                       if (!req->pdata_valid) {
+                               BX_OUTP(req->addr, (Bit32u) req->u.data, req->size);
+                       } else {
+                               for (i = 0; i < req->count; i++) {
+                                       unsigned long tmp;
+
+                                       BX_MEM_READ_PHYSICAL((Bit32u) req->u.pdata + (i * req->size), req->size, 
+                                                        &tmp);
+                                       BX_OUTP(req->addr, (Bit32u) tmp, req->size);
+                               }
+                       }
+                       
+               }
+       } else if (req->port_mm == 1){//memory map io
+               if (!req->pdata_valid) {
+                       if(req->dir == IOREQ_READ){//read
+                               BX_MEM_READ_PHYSICAL(req->addr, req->size, &req->u.data);
+                       } else if(req->dir == IOREQ_WRITE)//write
+                               BX_MEM_WRITE_PHYSICAL(req->addr, req->size, &req->u.data);
+               } else {
+                       //handle movs
+                       unsigned long tmp;
+                       if (req->dir == IOREQ_READ) {
+                               //BX_INFO(("<READ>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
+                               for (i = 0; i < req->count; i++) {
+                                       BX_MEM_READ_PHYSICAL(req->addr + (i * req->size), req->size, &tmp);
+                                       BX_MEM_WRITE_PHYSICAL((Bit32u) req->u.pdata + (i * req->size), req->size, &tmp);
+                               }
+                       } else if (req->dir == IOREQ_WRITE) {
+                               //BX_INFO(("<WRITE>addr:%llx, pdata:%llx, size: %x, count: %x\n", req->addr, req->u.pdata, req->size, req->count));
+                               for (i = 0; i < req->count; i++) {
+                                       BX_MEM_READ_PHYSICAL((Bit32u)req->u.pdata + (i * req->size), req->size, &tmp);
+                                       BX_MEM_WRITE_PHYSICAL(req->addr + (i * req->size), req->size, &tmp);
+                               }
+                       }
+               }
+       }
+       req->state = STATE_IORESP_READY;
+       send_event = 1;
+}
+
+void
+bx_cpu_c::handle_ioreq(void)
+{
+       ioreq_t *req = get_ioreq();
+       if (req)
+               dispatch_ioreq(req);
+}
+
+void
+bx_cpu_c::timer_handler(void)
+{
+       handle_ioreq();
+}
+
+#endif
+
+#define rdtscl(low) \
+     __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
+
+void
+bx_cpu_c::cpu_loop(int max_instr_count)
+{
+       Bit8u vector;
+       fd_set rfds;
+       unsigned long stime_usec;
+       struct timeval tv;
+       int retval;
+
+       /* Watch stdin (fd 0) to see when it has input. */
+       FD_ZERO(&rfds);
+
+       while (1) {
+               unsigned long t1, t2;
+
+               /* Wait up to one seconds. */
+               tv.tv_sec = 0;
+               tv.tv_usec = 100000;
+               FD_SET(evtchn_fd, &rfds);
+
+               send_event = 0;
+               rdtscl(t1);             
+               retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
+               rdtscl(t2);
+               if (retval == -1) {
+                       perror("select");
+                       return;
+               }
+               //stime_usec = 1000000 * (1 - tv.tv_sec)  - tv.tv_usec;
+               if (t2 > t1)
+                       BX_TICKN((t2 - t1) / 2000);     // should match ips in bochsrc
+               else
+                       BX_TICKN((MAXINT - t1 + t2) / 2000);    // should match ips in bochsrc
+               timer_handler();
+               if (BX_CPU_INTR) {
+#if BX_SUPPORT_APIC
+                       if (BX_CPU_THIS_PTR local_apic.INTR)
+                               vector = BX_CPU_THIS_PTR local_apic.acknowledge_int ();
+                       else
+                               vector = DEV_pic_iac(); // may set INTR with next interrupt
+#else
+                       // if no local APIC, always acknowledge the PIC.
+                       vector = DEV_pic_iac(); // may set INTR with next interrupt
+#endif
+                       interrupt(vector);
+               }
+
+               if (send_event) {
+                       int ret;
+                       ret = xc_evtchn_send(xc_handle, ioreq_port);
+                       if (ret == -1) {
+                               BX_ERROR(("evtchn_send failed on port: %d\n", ioreq_port));
+                       }
+               }
+       }
+}
+
+static __inline__ void set_bit(long nr, volatile void *addr)
+{
+       __asm__ __volatile__( "lock ; "
+               "btsl %1,%0"
+               :"=m" ((*(volatile long *)addr))
+               :"Ir" (nr));
+
+       return;
+}
+
+void
+bx_cpu_c::interrupt(Bit8u vector)
+{
+       unsigned long *intr, tscl;
+       int ret;
+
+       // Send a message on the event channel. Add the vector to the shared mem
+       // page.
+
+       rdtscl(tscl);
+       BX_INFO(("%lx: injecting vector: %x\n", tscl, vector));
+       intr = &(((vcpu_iodata_t *) shared_page)->vp_intr[0]);
+       set_bit(vector, intr);
+       
+       send_event = 1;
+}
+
+void
+bx_cpu_c::init(bx_mem_c*)
+{
+#ifdef BX_USE_VMX
+       if (evtchn_fd != -1)//the evtchn has been opened by another cpu object
+               return;
+
+       //use nonblock reading not polling, may change in future.
+       evtchn_fd = open("/dev/xen/evtchn", O_RDWR|O_NONBLOCK); 
+       if (evtchn_fd == -1) {
+               perror("open");
+               return;
+       }
+
+       BX_INFO(("listening to port: %d\n", ioreq_port));
+       /*unmask the wanted port -- bind*/
+       if (ioctl(evtchn_fd, ('E'<<8)|2, ioreq_port) == -1) {
+               perror("ioctl");
+               return;
+       }
+
+#if 0  
+       //register the reading evtchn function as timer
+       bx_pc_system.register_timer(this, timer_handler, 1000,//1000 us, may change
+                       1,//continuous timer
+                       1,//active
+                       "cpu reading evtchn handler");
+#endif
+
+#endif
+}
+
+void
+bx_cpu_c::reset(unsigned)
+{
+}
+
+void
+bx_cpu_c::atexit()
+{
+}
+
+void
+bx_cpu_c::set_INTR(unsigned value)
+{
+       BX_CPU_THIS_PTR INTR = value;
+}
+
+void
+bx_cpu_c::pagingA20Changed()
+{
+}
+
+bx_cpu_c::bx_cpu_c()
+{
+}
+
+bx_cpu_c::~bx_cpu_c()
+{
+}
diff --git a/tools/ioemu/iodev/crc32.cc b/tools/ioemu/iodev/crc32.cc
new file mode 100644 (file)
index 0000000..a20abaa
--- /dev/null
@@ -0,0 +1,49 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: crc32.cc,v 1.4 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* CRC-32 calculator
+ * Adapted from http://www.createwindow.org/programming/crc32/
+ */
+
+#include "crc32.h"
+
+CRC_Generator::CRC_Generator() {
+       init();
+}
+
+void CRC_Generator::init(void) {
+  Bit32u POLYNOMIAL = 0x04c11db7;
+  int i;
+
+  for(i = 0; i<0xFF; i++) {
+    int j;
+    crc32_table[i]=reflect(i,8) << 24;
+    for(j=0; j<8; j++)
+      crc32_table[i] = (crc32_table[i]<<1)^(crc32_table[i] & (1<<31) ? POLYNOMIAL : 0);
+    crc32_table[i] = reflect(crc32_table[i], 32);
+  }
+}
+
+Bit32u CRC_Generator::reflect(Bit32u ref, Bit8u ch) {
+  Bit32u value(0);
+  int i;
+
+  for(i=1; i<(ch+1); i++) {
+    if(ref & 1)
+      value |= 1 << (ch-i);
+    ref >>= 1;
+  }
+  return value;
+}
+
+Bit32u CRC_Generator::get_CRC(Bit8u * buf, Bit32u buflen) {
+  Bit32u ulCRC(0xFFFFFFFF);
+  Bit32u len(buflen);
+  Bit8u * buffer=(Bit8u *) buf;
+
+  while(len--)
+    ulCRC=(ulCRC>>8)^crc32_table[(ulCRC & 0xFF)^*buffer++];
+  return ulCRC ^ 0xFFFFFFFF;
+}
+
diff --git a/tools/ioemu/iodev/crc32.h b/tools/ioemu/iodev/crc32.h
new file mode 100644 (file)
index 0000000..faedaf8
--- /dev/null
@@ -0,0 +1,25 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: crc32.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* CRC-32 calculator
+ * Adapted from http://www.createwindow.org/programming/crc32/
+ */
+
+#ifndef _CRC_32_H_
+#define _CRC_32_H_
+
+#include "bochs.h"
+
+class CRC_Generator {
+private:
+  Bit32u crc32_table[256];
+  Bit32u reflect(Bit32u ref, Bit8u ch);
+public:
+  void init(void);
+  CRC_Generator();
+  Bit32u get_CRC(Bit8u * buf, Bit32u buflen);
+};
+
+#endif //_CRC_32_H_
+
diff --git a/tools/ioemu/iodev/devices.cc b/tools/ioemu/iodev/devices.cc
new file mode 100644 (file)
index 0000000..5dd7f5d
--- /dev/null
@@ -0,0 +1,685 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#include "bochs.h"
+#define LOG_THIS bx_devices.
+
+
+
+/* main memory size (in Kbytes)
+ * subtract 1k for extended BIOS area
+ * report only base memory, not extended mem
+ */
+#define BASE_MEMORY_IN_K  640
+
+
+bx_devices_c bx_devices;
+
+
+
+
+// constructor for bx_devices_c
+bx_devices_c::bx_devices_c(void)
+{
+  put("DEV");
+  settype(DEVLOG);
+
+#if BX_PCI_SUPPORT
+  pluginPciBridge = &stubPci;
+  pluginPci2IsaBridge = NULL;
+#if BX_PCI_VGA_SUPPORT
+    pluginPciVgaAdapter = NULL;
+#endif
+#if BX_PCI_USB_SUPPORT
+    pluginPciUSBAdapter = NULL;
+#endif                               
+#endif
+  pit = NULL;
+  pluginKeyboard = &stubKeyboard;
+  pluginDmaDevice = &stubDma;
+  pluginFloppyDevice = &stubFloppy;
+  pluginBiosDevice = NULL;
+  pluginCmosDevice = &stubCmos;
+  pluginSerialDevice = NULL;
+  pluginParallelDevice = NULL;
+  pluginUnmapped = NULL;
+  pluginVgaDevice = &stubVga;
+  pluginPicDevice = &stubPic;
+  pluginHardDrive = &stubHardDrive;
+  pluginSB16Device = NULL;
+  pluginNE2kDevice =&stubNE2k;
+  pluginExtFpuIrq = NULL;
+  pluginGameport = NULL;
+  g2h = NULL;
+#if BX_IODEBUG_SUPPORT
+  iodebug = NULL;
+#endif
+}
+
+
+bx_devices_c::~bx_devices_c(void)
+{
+  // nothing needed for now
+  BX_DEBUG(("Exit."));
+  timer_handle = BX_NULL_TIMER_HANDLE;
+}
+
+
+  void
+bx_devices_c::init(BX_MEM_C *newmem)
+{
+  unsigned i;
+
+  BX_DEBUG(("Init $Id: devices.cc,v 1.58 2003/12/26 13:53:39 vruppert Exp $"));
+  mem = newmem;
+
+  /* no read / write handlers defined */
+  num_read_handles = 0;
+  num_write_handles = 0;
+
+  /* set unused elements to appropriate values */
+  for (i=0; i < BX_MAX_IO_DEVICES; i++) {
+    io_read_handler[i].funct  = NULL;
+    io_write_handler[i].funct = NULL;
+    }
+
+  /* set no-default handlers, will be overwritten by the real default handler */
+  io_read_handler[BX_DEFAULT_IO_DEVICE].handler_name  = "Default";
+  io_read_handler[BX_DEFAULT_IO_DEVICE].funct         = &default_read_handler;
+  io_read_handler[BX_DEFAULT_IO_DEVICE].this_ptr      = NULL;
+  io_read_handler[BX_DEFAULT_IO_DEVICE].mask          = 7;
+  io_write_handler[BX_DEFAULT_IO_DEVICE].handler_name = "Default";
+  io_write_handler[BX_DEFAULT_IO_DEVICE].funct        = &default_write_handler;
+  io_write_handler[BX_DEFAULT_IO_DEVICE].this_ptr     = NULL;
+  io_write_handler[BX_DEFAULT_IO_DEVICE].mask         = 7;
+
+  /* set handlers to the default one */
+  for (i=0; i < 0x10000; i++) {
+    read_handler_id[i] = BX_DEFAULT_IO_DEVICE; 
+    write_handler_id[i] = BX_DEFAULT_IO_DEVICE;
+    }
+
+  for (i=0; i < BX_MAX_IRQS; i++) {
+    irq_handler_name[i] = NULL;
+    }
+
+  // BBD: At present, the only difference between "core" and "optional"
+  // plugins is that initialization and reset of optional plugins is handled
+  // by the plugin device list ().  Init and reset of core plugins is done
+  // "by hand" in this file.  Basically, we're using core plugins when we
+  // want to control the init order.
+  //
+  // CB: UNMAPPED and BIOSDEV should maybe be optional
+  PLUG_load_plugin(unmapped, PLUGTYPE_CORE);
+  PLUG_load_plugin(biosdev, PLUGTYPE_CORE);
+  PLUG_load_plugin(cmos, PLUGTYPE_CORE);
+  PLUG_load_plugin(dma, PLUGTYPE_CORE);
+  PLUG_load_plugin(pic, PLUGTYPE_CORE);
+  PLUG_load_plugin(vga, PLUGTYPE_CORE);
+  PLUG_load_plugin(floppy, PLUGTYPE_CORE);
+  PLUG_load_plugin(harddrv, PLUGTYPE_OPTIONAL);
+  PLUG_load_plugin(keyboard, PLUGTYPE_OPTIONAL);
+  if (is_serial_enabled ())
+    PLUG_load_plugin(serial, PLUGTYPE_OPTIONAL);
+  if (is_parallel_enabled ()) 
+    PLUG_load_plugin(parallel, PLUGTYPE_OPTIONAL);
+  PLUG_load_plugin(extfpuirq, PLUGTYPE_OPTIONAL);
+#if BX_SUPPORT_GAME
+  PLUG_load_plugin(gameport, PLUGTYPE_OPTIONAL);
+#endif
+
+  // Start with registering the default (unmapped) handler
+  pluginUnmapped->init ();
+
+  // PCI logic (i440FX)
+  if (bx_options.Oi440FXSupport->get ()) {
+#if BX_PCI_SUPPORT
+    PLUG_load_plugin(pci, PLUGTYPE_OPTIONAL);
+    PLUG_load_plugin(pci2isa, PLUGTYPE_OPTIONAL);
+#if BX_PCI_VGA_SUPPORT
+    PLUG_load_plugin(pcivga, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_PCI_USB_SUPPORT
+    PLUG_load_plugin(pciusb, PLUGTYPE_OPTIONAL);
+#endif
+#else
+    BX_ERROR(("Bochs is not compiled with PCI support"));
+#endif
+  }
+
+#if BX_SUPPORT_APIC
+    // I/O APIC 82093AA
+    ioapic = & bx_ioapic;
+    ioapic->init ();
+#endif
+
+  // BIOS log 
+  pluginBiosDevice->init ();
+
+  // CMOS RAM & RTC
+  pluginCmosDevice->init ();
+
+  /*--- 8237 DMA ---*/
+  pluginDmaDevice->init();
+
+  //--- FLOPPY ---
+  pluginFloppyDevice->init();
+
+  //--- SOUND ---
+  if (bx_options.sb16.Opresent->get ()) {
+#if BX_SUPPORT_SB16
+    PLUG_load_plugin(sb16, PLUGTYPE_OPTIONAL);
+#else
+    BX_ERROR(("Bochs is not compiled with SB16 support"));
+#endif
+  }
+
+  /*--- VGA adapter ---*/
+  pluginVgaDevice->init ();
+
+  /*--- 8259A PIC ---*/
+  pluginPicDevice->init();
+
+  /*--- 8254 PIT ---*/
+  pit = & bx_pit;
+  pit->init();
+
+  bx_virt_timer.init();
+
+  bx_slowdown_timer.init();
+
+#if BX_IODEBUG_SUPPORT
+  iodebug = &bx_iodebug;
+  iodebug->init();
+#endif
+
+  // NE2000 NIC
+  if (bx_options.ne2k.Opresent->get ()) {
+#if BX_NE2K_SUPPORT
+    PLUG_load_plugin(ne2k, PLUGTYPE_OPTIONAL);
+#else
+    BX_ERROR(("Bochs is not compiled with NE2K support"));
+#endif
+  }
+
+#if 0
+  // Guest to Host interface.  Used with special guest drivers
+  // which move data to/from the host environment.
+  g2h = &bx_g2h;
+  g2h->init();
+#endif
+
+  // system hardware
+  register_io_read_handler( this,
+                            &read_handler,
+                            0x0092,
+                            "Port 92h System Control", 1 );
+  register_io_write_handler(this,
+                            &write_handler,
+                            0x0092,
+                            "Port 92h System Control", 1 );
+
+  // misc. CMOS
+  Bit32u extended_memory_in_k = mem->get_memory_in_k() > 1024 ? (mem->get_memory_in_k() - 1024) : 0;
+  if (extended_memory_in_k > 0xffff) extended_memory_in_k = 0xffff;
+
+  DEV_cmos_set_reg(0x15, (Bit8u) BASE_MEMORY_IN_K);
+  DEV_cmos_set_reg(0x16, (Bit8u) (BASE_MEMORY_IN_K >> 8));
+  DEV_cmos_set_reg(0x17, (Bit8u) (extended_memory_in_k & 0xff) );
+  DEV_cmos_set_reg(0x18, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) );
+  DEV_cmos_set_reg(0x30, (Bit8u) (extended_memory_in_k & 0xff) );
+  DEV_cmos_set_reg(0x31, (Bit8u) ((extended_memory_in_k >> 8) & 0xff) );
+
+  Bit32u extended_memory_in_64k = mem->get_memory_in_k() > 16384 ? (mem->get_memory_in_k() - 16384) / 64 : 0;
+  if (extended_memory_in_64k > 0xffff) extended_memory_in_64k = 0xffff;
+
+  DEV_cmos_set_reg(0x34, (Bit8u) (extended_memory_in_64k & 0xff) );
+  DEV_cmos_set_reg(0x35, (Bit8u) ((extended_memory_in_64k >> 8) & 0xff) );
+
+  if (timer_handle != BX_NULL_TIMER_HANDLE) {
+    timer_handle = bx_pc_system.register_timer( this, timer_handler,
+      (unsigned) BX_IODEV_HANDLER_PERIOD, 1, 1, "devices.cc");
+  }
+
+  // Clear fields for bulk IO acceleration transfers.
+  bulkIOHostAddr = 0;
+  bulkIOQuantumsRequested = 0;
+  bulkIOQuantumsTransferred = 0;
+
+  bx_init_plugins();
+
+  /* now perform checksum of CMOS memory */
+  DEV_cmos_checksum();
+}
+
+
+  void
+bx_devices_c::reset(unsigned type)
+{
+  pluginUnmapped->reset(type);
+#if BX_PCI_SUPPORT
+  if (bx_options.Oi440FXSupport->get ()) {
+    pluginPciBridge->reset(type);
+    pluginPci2IsaBridge->reset(type);
+#if BX_PCI_VGA_SUPPORT
+    pluginPciVgaAdapter->reset(type);
+#endif
+#if BX_PCI_USB_SUPPORT
+    pluginPciUSBAdapter->reset(type);
+#endif
+  }
+#endif
+#if BX_SUPPORT_IOAPIC
+  ioapic->reset (type);
+#endif
+  pluginBiosDevice->reset(type);
+  pluginCmosDevice->reset(type);
+  pluginDmaDevice->reset(type);
+  pluginFloppyDevice->reset(type);
+#if BX_SUPPORT_SB16
+  if (pluginSB16Device) pluginSB16Device->reset(type);
+#endif
+  pluginVgaDevice->reset(type);
+  pluginPicDevice->reset(type);
+  pit->reset(type);
+  bx_slowdown_timer.reset(type);
+#if BX_IODEBUG_SUPPORT
+  iodebug->reset(type);
+#endif
+#if BX_NE2K_SUPPORT
+  if (pluginNE2kDevice) pluginNE2kDevice->reset(type);
+#endif
+
+  bx_reset_plugins(type);
+}
+
+
+  Bit32u
+bx_devices_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_DEV_SMF
+  bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+  return( class_ptr->port92_read(address, io_len) );
+}
+
+
+  Bit32u
+bx_devices_c::port92_read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_DEV_SMF
+
+  BX_DEBUG(("port92h read partially supported!!!"));
+  BX_DEBUG(("  returning %02x", (unsigned) (BX_GET_ENABLE_A20() << 1)));
+  return(BX_GET_ENABLE_A20() << 1);
+}
+
+
+  void
+bx_devices_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_DEV_SMF
+  bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+  class_ptr->port92_write(address, value, io_len);
+}
+
+  void
+bx_devices_c::port92_write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_DEV_SMF
+  bx_bool bx_cpu_reset;
+
+  BX_DEBUG(("port92h write of %02x partially supported!!!",
+    (unsigned) value));
+  BX_DEBUG(("A20: set_enable_a20() called"));
+  BX_SET_ENABLE_A20( (value & 0x02) >> 1 );
+  BX_DEBUG(("A20: now %u", (unsigned) BX_GET_ENABLE_A20()));
+  bx_cpu_reset  = (value & 0x01); /* high speed reset */
+  if (bx_cpu_reset) {
+    BX_PANIC(("PORT 92h write: CPU reset requested!"));
+    }
+}
+
+
+// This defines a no-default read handler, 
+// so Bochs does not segfault if unmapped is not loaded
+  Bit32u
+bx_devices_c::default_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+  UNUSED(this_ptr);
+  BX_PANIC(("No default io-read handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len));
+  return 0xffffffff;
+}
+
+// This defines a no-default write handler, 
+// so Bochs does not segfault if unmapped is not loaded
+  void
+bx_devices_c::default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+  UNUSED(this_ptr);
+  BX_PANIC(("No default io-write handler found for 0x%04x/%d. Unmapped io-device not loaded ?", address, io_len));
+}
+
+  void
+bx_devices_c::timer_handler(void *this_ptr)
+{
+  bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
+
+  class_ptr->timer();
+}
+
+  void
+bx_devices_c::timer()
+{
+#if (BX_USE_NEW_PIT==0)
+  if ( pit->periodic( BX_IODEV_HANDLER_PERIOD ) ) {
+    // This is a hack to make the IRQ0 work
+    DEV_pic_lower_irq(0);
+    DEV_pic_raise_irq(0);
+    }
+#endif
+
+
+  // separate calls to bx_gui->handle_events from the keyboard code.
+  {
+    static int multiple=0;
+    if ( ++multiple==10)
+    {
+      multiple=0;
+      SIM->periodic ();
+      if (!BX_CPU(0)->kill_bochs_request)
+       bx_gui->handle_events();
+    }
+  }
+
+// KPL Removed lapic periodic timer registration here.
+}
+
+
+  bx_bool
+bx_devices_c::register_irq(unsigned irq, const char *name)
+{
+  if (irq >= BX_MAX_IRQS) {
+    BX_PANIC(("IO device %s registered with IRQ=%d above %u",
+             name, irq, (unsigned) BX_MAX_IRQS-1));
+    return false;
+    }
+  if (irq_handler_name[irq]) {
+    BX_PANIC(("IRQ %u conflict, %s with %s", irq,
+      irq_handler_name[irq], name));
+    return false;
+    }
+  irq_handler_name[irq] = name;
+  return true;
+}
+
+  bx_bool
+bx_devices_c::unregister_irq(unsigned irq, const char *name)
+{
+  if (irq >= BX_MAX_IRQS) {
+    BX_PANIC(("IO device %s tried to unregister IRQ %d above %u",
+             name, irq, (unsigned) BX_MAX_IRQS-1));
+    return false;
+    }
+
+  if (!irq_handler_name[irq]) {
+    BX_INFO(("IO device %s tried to unregister IRQ %d, not registered",
+             name, irq));
+    return false;
+  }
+
+  if (strcmp(irq_handler_name[irq], name)) {
+    BX_INFO(("IRQ %u not registered to %s but to %s", irq,
+      name, irq_handler_name[irq]));
+    return false;
+    }
+  irq_handler_name[irq] = NULL;
+  return true;
+}
+
+  bx_bool
+bx_devices_c::register_io_read_handler( void *this_ptr, bx_read_handler_t f,
+                                        Bit32u addr, const char *name, Bit8u mask )
+{
+  unsigned handle;
+
+  addr &= 0x0000ffff;
+
+  /* first find existing handle for function or create new one */
+  for (handle=0; handle < num_read_handles; handle++) {
+    if ((io_read_handler[handle].funct == f) &&
+        (io_read_handler[handle].mask == mask)) break;
+    }
+
+  if (handle >= num_read_handles) {
+    /* no existing handle found, create new one */
+    if (num_read_handles >= BX_DEFAULT_IO_DEVICE) {
+      BX_INFO(("too many IO devices installed."));
+      BX_PANIC(("  try increasing BX_MAX_IO_DEVICES"));
+      }
+    num_read_handles++;
+    io_read_handler[handle].funct          = f;
+    io_read_handler[handle].this_ptr       = this_ptr;
+    io_read_handler[handle].handler_name   = name;
+    io_read_handler[handle].mask           = mask;
+    }
+
+  /* change table to reflect new handler id for that address */
+  if (read_handler_id[addr] < BX_DEFAULT_IO_DEVICE) {
+    // another handler is already registered for that address
+    BX_ERROR(("IO device address conflict(read) at IO address %Xh",
+      (unsigned) addr));
+    BX_ERROR(("  conflicting devices: %s & %s",
+      io_read_handler[handle].handler_name, io_read_handler[read_handler_id[addr]].handler_name));
+    return false; // address not available, return false.
+    }
+  read_handler_id[addr] = handle;
+  return true; // address mapped successfully
+}
+
+
+
+  bx_bool
+bx_devices_c::register_io_write_handler( void *this_ptr, bx_write_handler_t f,
+                                        Bit32u addr, const char *name, Bit8u mask )
+{
+  unsigned handle;
+
+  addr &= 0x0000ffff;
+
+  /* first find existing handle for function or create new one */
+  for (handle=0; handle < num_write_handles; handle++) {
+    if ((io_write_handler[handle].funct == f) &&
+        (io_write_handler[handle].mask == mask)) break;
+    }
+
+  if (handle >= num_write_handles) {
+    /* no existing handle found, create new one */
+    if (num_write_handles >= BX_DEFAULT_IO_DEVICE) {
+      BX_INFO(("too many IO devices installed."));
+      BX_PANIC(("  try increasing BX_MAX_IO_DEVICES"));
+      }
+    num_write_handles++;
+    io_write_handler[handle].funct          = f;
+    io_write_handler[handle].this_ptr       = this_ptr;
+    io_write_handler[handle].handler_name   = name;
+    io_write_handler[handle].mask           = mask;
+    }
+
+  /* change table to reflect new handler id for that address */
+  if (write_handler_id[addr] < BX_DEFAULT_IO_DEVICE) {
+    // another handler is already registered for that address
+    BX_ERROR(("IO device address conflict(write) at IO address %Xh",
+      (unsigned) addr));
+    BX_ERROR(("  conflicting devices: %s & %s",
+      io_write_handler[handle].handler_name, io_write_handler[write_handler_id[addr]].handler_name));
+    return false; //unable to map iodevice.
+    }
+  write_handler_id[addr] = handle;
+  return true; // done!
+}
+
+
+// Registration of default handlers (mainly be the unmapped device)
+// The trick here is to define a handler for the max index, so
+// unregisterd io address will get handled by the default function
+// This will be helpful when we want to unregister io handlers
+
+  bx_bool
+bx_devices_c::register_default_io_read_handler( void *this_ptr, bx_read_handler_t f,
+                                        const char *name, Bit8u mask )
+{
+  unsigned handle;
+
+  /* handle is fixed to the default I/O device */
+  handle = BX_DEFAULT_IO_DEVICE;
+
+  if (strcmp(io_read_handler[handle].handler_name, "Default")) {
+    BX_ERROR(("Default io read handler already registered '%s'",io_read_handler[handle].handler_name));
+    return false;
+    }
+
+  io_read_handler[handle].funct          = f;
+  io_read_handler[handle].this_ptr       = this_ptr;
+  io_read_handler[handle].handler_name   = name;
+  io_read_handler[handle].mask           = mask;
+
+  return true; 
+}
+
+
+
+  bx_bool
+bx_devices_c::register_default_io_write_handler( void *this_ptr, bx_write_handler_t f,
+                                        const char *name, Bit8u mask )
+{
+  unsigned handle;
+
+  /* handle is fixed to the MAX */
+  handle = BX_DEFAULT_IO_DEVICE;
+
+  if (strcmp(io_write_handler[handle].handler_name, "Default")) {
+    BX_ERROR(("Default io write handler already registered '%s'",io_write_handler[handle].handler_name));
+    return false;
+    }
+
+  io_write_handler[handle].funct          = f;
+  io_write_handler[handle].this_ptr       = this_ptr;
+  io_write_handler[handle].handler_name   = name;
+  io_write_handler[handle].mask           = mask;
+
+  return true; 
+}
+
+
+
+/*
+ * Read a byte of data from the IO memory address space
+ */
+
+  Bit32u BX_CPP_AttrRegparmN(2)
+bx_devices_c::inp(Bit16u addr, unsigned io_len)
+{
+  Bit8u handle;
+  Bit32u ret;
+
+  BX_INSTR_INP(addr, io_len);
+
+  handle = read_handler_id[addr];
+  if ((io_read_handler[handle].funct != NULL) &&
+      (io_read_handler[handle].mask & io_len)) {
+    ret = (* io_read_handler[handle].funct)(io_read_handler[handle].this_ptr,
+                             (Bit32u) addr, io_len);
+  } else {
+    switch (io_len) {
+      case 1: ret = 0xff; break;
+      case 2: ret = 0xffff; break;
+      default: ret = 0xffffffff; break;
+    }
+    BX_ERROR(("read from port 0x%04x with len %d returns 0x%x", addr, io_len, ret));
+  }
+  BX_INSTR_INP2(addr, io_len, ret);
+  BX_DBG_IO_REPORT(addr, io_len, BX_READ, ret);
+
+  return(ret);
+}
+
+
+/*
+ * Write a byte of data to the IO memory address space.
+ */
+
+  void BX_CPP_AttrRegparmN(3)
+bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned io_len)
+{
+  Bit8u handle;
+
+  BX_INSTR_OUTP(addr, io_len);
+  BX_INSTR_OUTP2(addr, io_len, value);
+
+  BX_DBG_IO_REPORT(addr, io_len, BX_WRITE, value);
+  handle = write_handler_id[addr];
+  if ((io_write_handler[handle].funct != NULL) &&
+      (io_write_handler[handle].mask & io_len)) {
+    (* io_write_handler[handle].funct)(io_write_handler[handle].this_ptr,
+                       (Bit32u) addr, value, io_len);
+  } else {
+    BX_ERROR(("write to port 0x%04x with len %d ignored", addr, io_len));
+  }
+}
+
+bx_bool bx_devices_c::is_serial_enabled ()
+{
+  for (int i=0; i<BX_N_SERIAL_PORTS; i++) {
+    if (SIM->get_param_bool (BXP_COMx_ENABLED(i+1))->get())
+      return true;
+  }
+  return false;
+}
+
+bx_bool bx_devices_c::is_usb_enabled ()
+{
+  for (int i=0; i<BX_N_USB_HUBS; i++) {
+    if (SIM->get_param_bool (BXP_USBx_ENABLED(i+1))->get())
+       return true;
+  }
+  return false;
+}
+
+bx_bool bx_devices_c::is_parallel_enabled ()
+{
+  for (int i=0; i<BX_N_PARALLEL_PORTS; i++) {
+    if (SIM->get_param_bool (BXP_PARPORTx_ENABLED(i+1))->get())
+      return true;
+  }
+  return false;
+}
diff --git a/tools/ioemu/iodev/dma.cc b/tools/ioemu/iodev/dma.cc
new file mode 100644 (file)
index 0000000..9b99bad
--- /dev/null
@@ -0,0 +1,816 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: dma.cc,v 1.30 2003/07/31 15:29:34 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theDmaDevice->
+
+#define DMA_MODE_DEMAND  0
+#define DMA_MODE_SINGLE  1
+#define DMA_MODE_BLOCK   2
+#define DMA_MODE_CASCADE 3
+
+bx_dma_c *theDmaDevice = NULL;
+
+  int
+libdma_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theDmaDevice = new bx_dma_c ();
+  bx_devices.pluginDmaDevice = theDmaDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theDmaDevice, BX_PLUGIN_DMA);
+  return(0); // Success
+}
+
+  void
+libdma_LTX_plugin_fini(void)
+{
+}
+
+bx_dma_c::bx_dma_c(void)
+{
+  put("DMA");
+  settype(DMALOG);
+}
+
+bx_dma_c::~bx_dma_c(void)
+{
+       BX_DEBUG(("Exit."));
+}
+
+  unsigned
+bx_dma_c::registerDMA8Channel(
+    unsigned channel,
+    void (* dmaRead)(Bit8u *data_byte),
+    void (* dmaWrite)(Bit8u *data_byte),
+    const char *name
+    )
+{
+  if (channel > 3) {
+    BX_PANIC(("registerDMA8Channel: invalid channel number(%u).", channel));
+    return 0; // Fail.
+    }
+  if (BX_DMA_THIS s[0].chan[channel].used) {
+    BX_PANIC(("registerDMA8Channel: channel(%u) already in use.", channel));
+    return 0; // Fail.
+    }
+  BX_INFO(("channel %u used by %s", channel, name));
+  BX_DMA_THIS h[channel].dmaRead8  = dmaRead;
+  BX_DMA_THIS h[channel].dmaWrite8 = dmaWrite;
+  BX_DMA_THIS s[0].chan[channel].used = 1;
+  return 1; // OK.
+}
+
+  unsigned
+bx_dma_c::registerDMA16Channel(
+    unsigned channel,
+    void (* dmaRead)(Bit16u *data_word),
+    void (* dmaWrite)(Bit16u *data_word),
+    const char *name
+    )
+{
+  if ((channel < 4) || (channel > 7)) {
+    BX_PANIC(("registerDMA16Channel: invalid channel number(%u).", channel));
+    return 0; // Fail.
+    }
+  if (BX_DMA_THIS s[1].chan[channel & 0x03].used) {
+    BX_PANIC(("registerDMA16Channel: channel(%u) already in use.", channel));
+    return 0; // Fail.
+    }
+  BX_INFO(("channel %u used by %s", channel, name));
+  channel &= 0x03;
+  BX_DMA_THIS h[channel].dmaRead16  = dmaRead;
+  BX_DMA_THIS h[channel].dmaWrite16 = dmaWrite;
+  BX_DMA_THIS s[1].chan[channel].used = 1;
+  return 1; // OK.
+}
+
+  unsigned
+bx_dma_c::unregisterDMAChannel(unsigned channel)
+{
+  bx_bool ma_sl = (channel > 3);
+  BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used = 0;
+  BX_INFO(("channel %u no longer used", channel));
+  return 1;
+}
+
+  unsigned
+bx_dma_c::get_TC(void)
+{
+  return BX_DMA_THIS TC;
+}
+
+
+  void
+bx_dma_c::init(void)
+{
+  unsigned c, i, j;
+  BX_DEBUG(("Init $Id: dma.cc,v 1.30 2003/07/31 15:29:34 vruppert Exp $"));
+
+  /* 8237 DMA controller */
+
+  for (i=0; i < 2; i++) {
+    for (j=0; j < 4; j++) {
+      BX_DMA_THIS s[i].DRQ[j] = 0;
+      BX_DMA_THIS s[i].DACK[j] = 0;
+      }
+    }
+  BX_DMA_THIS HLDA = 0;
+  BX_DMA_THIS TC = 0;
+
+  // 0000..000F
+  for (i=0x0000; i<=0x000F; i++) {
+    DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
+    DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
+    }
+
+  // 00081..008F
+  for (i=0x0081; i<=0x008F; i++) {
+    DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
+    DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
+    }
+
+  // 000C0..00DE
+  for (i=0x00C0; i<=0x00DE; i+=2) {
+    DEV_register_ioread_handler(this, read_handler, i, "DMA controller", 1);
+    DEV_register_iowrite_handler(this, write_handler, i, "DMA controller", 3);
+    }
+
+
+  for (i=0; i<2; i++) {
+    for (c=0; c<4; c++) {
+      BX_DMA_THIS s[i].chan[c].mode.mode_type = 0;         // demand mode
+      BX_DMA_THIS s[i].chan[c].mode.address_decrement = 0; // address increment
+      BX_DMA_THIS s[i].chan[c].mode.autoinit_enable = 0;   // autoinit disable
+      BX_DMA_THIS s[i].chan[c].mode.transfer_type = 0;     // verify
+      BX_DMA_THIS s[i].chan[c].base_address = 0;
+      BX_DMA_THIS s[i].chan[c].current_address = 0;
+      BX_DMA_THIS s[i].chan[c].base_count = 0;
+      BX_DMA_THIS s[i].chan[c].current_count = 0;
+      BX_DMA_THIS s[i].chan[c].page_reg = 0;
+      BX_DMA_THIS s[i].chan[c].used = 0;
+      }
+    }
+  BX_DMA_THIS s[1].chan[0].used = 1; // cascade channel in use
+  BX_INFO(("channel 4 used by cascade"));
+}
+
+  void
+bx_dma_c::reset(unsigned type)
+{
+  reset_controller(0);
+  reset_controller(1);
+}
+
+  void
+bx_dma_c::reset_controller(unsigned num)
+{
+  BX_DMA_THIS s[num].mask[0] = 1;
+  BX_DMA_THIS s[num].mask[1] = 1;
+  BX_DMA_THIS s[num].mask[2] = 1;
+  BX_DMA_THIS s[num].mask[3] = 1;
+  BX_DMA_THIS s[num].command_reg = 0;
+  BX_DMA_THIS s[num].status_reg = 0;
+  BX_DMA_THIS s[num].request_reg = 0;
+  BX_DMA_THIS s[num].temporary_reg = 0;
+  BX_DMA_THIS s[num].flip_flop = 0;
+}
+
+  // index to find channel from register number (only [0],[1],[2],[6] used)
+  Bit8u channelindex[7] = {2, 3, 1, 0, 0, 0, 0};
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_dma_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_DMA_SMF
+  bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+  /* 8237 DMA controller */
+  Bit32u BX_CPP_AttrRegparmN(2)
+bx_dma_c::read( Bit32u   address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_DMA_SMF
+
+  Bit8u retval;
+  Bit8u channel;
+  bx_bool ma_sl;
+
+  BX_DEBUG(("read addr=%04x", (unsigned) address));
+
+#if BX_DMA_FLOPPY_IO < 1
+  /* if we're not supporting DMA/floppy IO just return a bogus value */
+  return(0xff);
+#endif
+
+  switch (address) {
+    case 0x00: /* DMA-1 current address, channel 0 */
+    case 0x02: /* DMA-1 current address, channel 1 */
+    case 0x04: /* DMA-1 current address, channel 2 */
+    case 0x06: /* DMA-1 current address, channel 3 */
+    case 0xc0: /* DMA-2 current address, channel 0 */
+    case 0xc4: /* DMA-2 current address, channel 1 */
+    case 0xc8: /* DMA-2 current address, channel 2 */
+    case 0xcc: /* DMA-2 current address, channel 3 */
+      ma_sl = (address >= 0xc0);
+      channel = (address >> (1 + ma_sl)) & 0x03;
+      if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
+        BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+        return(BX_DMA_THIS s[ma_sl].chan[channel].current_address & 0xff);
+        }
+      else {
+        BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+        return(BX_DMA_THIS s[ma_sl].chan[channel].current_address >> 8);
+        }
+
+    case 0x01: /* DMA-1 current count, channel 0 */
+    case 0x03: /* DMA-1 current count, channel 1 */
+    case 0x05: /* DMA-1 current count, channel 2 */
+    case 0x07: /* DMA-1 current count, channel 3 */
+    case 0xc2: /* DMA-2 current count, channel 0 */
+    case 0xc6: /* DMA-2 current count, channel 1 */
+    case 0xca: /* DMA-2 current count, channel 2 */
+    case 0xce: /* DMA-2 current count, channel 3 */
+      ma_sl = (address >= 0xc2);
+      channel = (address >> (1 + ma_sl)) & 0x03;
+      if (BX_DMA_THIS s[ma_sl].flip_flop==0) {
+        BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+        return(BX_DMA_THIS s[ma_sl].chan[channel].current_count & 0xff);
+        }
+      else {
+        BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+        return(BX_DMA_THIS s[ma_sl].chan[channel].current_count >> 8);
+        }
+
+    case 0x08: // DMA-1 Status Register
+    case 0xd0: // DMA-2 Status Register
+      // bit 7: 1 = channel 3 request
+      // bit 6: 1 = channel 2 request
+      // bit 5: 1 = channel 1 request
+      // bit 4: 1 = channel 0 request
+      // bit 3: 1 = channel 3 has reached terminal count
+      // bit 2: 1 = channel 2 has reached terminal count
+      // bit 1: 1 = channel 1 has reached terminal count
+      // bit 0: 1 = channel 0 has reached terminal count
+      // reading this register clears lower 4 bits (hold flags)
+      ma_sl = (address == 0xd0);
+      retval = BX_DMA_THIS s[ma_sl].status_reg;
+      BX_DMA_THIS s[ma_sl].status_reg &= 0xf0;
+      return(retval);
+      break;
+    case 0x0d: // DMA-1: temporary register
+    case 0xda: // DMA-2: temporary register
+      ma_sl = (address == 0xda);
+      BX_ERROR(("DMA-%d: read of temporary register", ma_sl+1));
+      // Note: write to 0x0D clears temporary register
+      return(0);
+      break;
+
+    case 0x0081: // DMA-1 page register, channel 2
+    case 0x0082: // DMA-1 page register, channel 3
+    case 0x0083: // DMA-1 page register, channel 1
+    case 0x0087: // DMA-1 page register, channel 0
+      channel = channelindex[address - 0x81];
+      return( BX_DMA_THIS s[0].chan[channel].page_reg );
+
+    case 0x0089: // DMA-2 page register, channel 2
+    case 0x008a: // DMA-2 page register, channel 3
+    case 0x008b: // DMA-2 page register, channel 1
+    case 0x008f: // DMA-2 page register, channel 0
+      channel = channelindex[address - 0x89];
+      return( BX_DMA_THIS s[1].chan[channel].page_reg );
+
+    case 0x0084:
+    case 0x0085:
+    case 0x0086:
+    case 0x0088:
+    case 0x008c:
+    case 0x008d:
+    case 0x008e:
+      BX_DEBUG(("read: extra page register 0x%04x unsupported", (unsigned) address));
+      return(0);
+
+    default:
+      BX_ERROR(("read: unsupported address=%04x", (unsigned) address));
+      return(0);
+    }
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_dma_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_DMA_SMF
+  bx_dma_c *class_ptr = (bx_dma_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+
+  /* 8237 DMA controller */
+  void BX_CPP_AttrRegparmN(3)
+bx_dma_c::write(Bit32u   address, Bit32u   value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_DMA_SMF
+  Bit8u set_mask_bit;
+  Bit8u channel;
+  bx_bool ma_sl;
+
+  if (io_len > 1) {
+    if ( (io_len == 2) && (address == 0x0b) ) {
+#if BX_USE_DMA_SMF
+      BX_DMA_THIS write_handler(NULL, address,   value & 0xff, 1);
+      BX_DMA_THIS write_handler(NULL, address+1, value >> 8,   1);
+#else
+      BX_DMA_THIS write(address,   value & 0xff, 1);
+      BX_DMA_THIS write(address+1, value >> 8,   1);
+#endif
+      return;
+      }
+
+    BX_ERROR(("io write to address %08x, len=%u",
+             (unsigned) address, (unsigned) io_len));
+    return;
+    }
+
+  BX_DEBUG(("write: address=%04x value=%02x",
+      (unsigned) address, (unsigned) value));
+
+#if BX_DMA_FLOPPY_IO < 1
+  /* if we're not supporting DMA/floppy IO just return */
+  return;
+#endif
+
+  switch (address) {
+    case 0x00:
+    case 0x02:
+    case 0x04:
+    case 0x06:
+    case 0xc0:
+    case 0xc4:
+    case 0xc8:
+    case 0xcc:
+      ma_sl = (address >= 0xc0);
+      channel = (address >> (1 + ma_sl)) & 0x03;
+      BX_DEBUG(("  DMA-%d base and current address, channel %d", ma_sl+1, channel));
+      if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
+        BX_DMA_THIS s[ma_sl].chan[channel].base_address = value;
+        BX_DMA_THIS s[ma_sl].chan[channel].current_address = value;
+        }
+      else { /* 2nd byte */
+        BX_DMA_THIS s[ma_sl].chan[channel].base_address |= (value << 8);
+        BX_DMA_THIS s[ma_sl].chan[channel].current_address |= (value << 8);
+        BX_DEBUG(("    base = %04x",
+            (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_address));
+        BX_DEBUG(("    curr = %04x",
+            (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_address));
+        }
+      BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+      return;
+      break;
+
+    case 0x01:
+    case 0x03:
+    case 0x05:
+    case 0x07:
+    case 0xc2:
+    case 0xc6:
+    case 0xca:
+    case 0xce:
+      ma_sl = (address >= 0xc2);
+      channel = (address >> (1 + ma_sl)) & 0x03;
+      BX_DEBUG(("  DMA-%d base and current count, channel %d", ma_sl+1, channel));
+      if (BX_DMA_THIS s[ma_sl].flip_flop==0) { /* 1st byte */
+        BX_DMA_THIS s[ma_sl].chan[channel].base_count = value;
+        BX_DMA_THIS s[ma_sl].chan[channel].current_count = value;
+        }
+      else { /* 2nd byte */
+        BX_DMA_THIS s[ma_sl].chan[channel].base_count |= (value << 8);
+        BX_DMA_THIS s[ma_sl].chan[channel].current_count |= (value << 8);
+        BX_DEBUG(("    base = %04x",
+            (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
+        BX_DEBUG(("    curr = %04x",
+            (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].current_count));
+        }
+      BX_DMA_THIS s[ma_sl].flip_flop = !BX_DMA_THIS s[ma_sl].flip_flop;
+      return;
+      break;
+
+    case 0x08: /* DMA-1: command register */
+    case 0xd0: /* DMA-2: command register */
+      ma_sl = (address == 0xd0);
+      if (value != 0x00)
+        BX_ERROR(("write to command register: value(%02xh) not 0x00",
+          (unsigned) value));
+      BX_DMA_THIS s[ma_sl].command_reg = value;
+      return;
+      break;
+
+    case 0x09: // DMA-1: request register
+    case 0xd2: // DMA-2: request register
+      ma_sl = (address == 0xd2);
+      channel = value & 0x03;
+      BX_ERROR(("DMA-%d: write to request register (%02x)", ma_sl+1, (unsigned) value));
+      // note: write to 0x0d clears this register
+      if (value & 0x04) {
+        // set request bit
+        BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
+        BX_DEBUG(("DMA-%d: set request bit for channel %u", ma_sl+1, (unsigned) channel));
+        }
+      else {
+        // clear request bit
+        BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
+        BX_DEBUG(("DMA-%d: cleared request bit for channel %u", ma_sl+1, (unsigned) channel));
+        }
+      control_HRQ(ma_sl);
+      return;
+      break;
+
+    case 0x0a:
+    case 0xd4:
+      ma_sl = (address == 0xd4);
+      set_mask_bit = value & 0x04;
+      channel = value & 0x03;
+      BX_DMA_THIS s[ma_sl].mask[channel] = (set_mask_bit > 0);
+      BX_DEBUG(("DMA-%d: set_mask_bit=%u, channel=%u, mask now=%02xh", ma_sl+1,
+          (unsigned) set_mask_bit, (unsigned) channel, (unsigned) BX_DMA_THIS s[ma_sl].mask[channel]));
+      control_HRQ(ma_sl);
+      return;
+      break;
+
+    case 0x0b: /* DMA-1 mode register */
+    case 0xd6: /* DMA-2 mode register */
+      ma_sl = (address == 0xd6);
+      channel = value & 0x03;
+      BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type = (value >> 6) & 0x03;
+      BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement = (value >> 5) & 0x01;
+      BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable = (value >> 4) & 0x01;
+      BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type = (value >> 2) & 0x03;
+      BX_DEBUG(("DMA-%d: mode register[%u] = %02x", ma_sl+1,
+          (unsigned) channel, (unsigned) value));
+      return;
+      break;
+
+    case 0x0c: /* DMA-1 clear byte flip/flop */
+    case 0xd8: /* DMA-2 clear byte flip/flop */
+      ma_sl = (address == 0xd8);
+      BX_DEBUG(("DMA-%d: clear flip/flop", ma_sl+1));
+      BX_DMA_THIS s[ma_sl].flip_flop = 0;
+      return;
+      break;
+
+    case 0x0d: // DMA-1: master clear
+    case 0xda: // DMA-2: master clear
+      ma_sl = (address == 0xda);
+      BX_DEBUG(("DMA-%d: master clear", ma_sl+1));
+      // writing any value to this port resets DMA controller 1 / 2
+      // same action as a hardware reset
+      // mask register is set (chan 0..3 disabled)
+      // command, status, request, temporary, and byte flip-flop are all cleared
+      reset_controller(ma_sl);
+      return;
+      break;
+
+    case 0x0e: // DMA-1: clear mask register
+    case 0xdc: // DMA-2: clear mask register
+      ma_sl = (address == 0xdc);
+      BX_DEBUG(("DMA-%d: clear mask register", ma_sl+1));
+      BX_DMA_THIS s[ma_sl].mask[0] = 0;
+      BX_DMA_THIS s[ma_sl].mask[1] = 0;
+      BX_DMA_THIS s[ma_sl].mask[2] = 0;
+      BX_DMA_THIS s[ma_sl].mask[3] = 0;
+      control_HRQ(ma_sl);
+      return;
+      break;
+
+    case 0x0f: // DMA-1: write all mask bits
+    case 0xde: // DMA-2: write all mask bits
+      ma_sl = (address == 0xde);
+      BX_DEBUG(("DMA-%d: write all mask bits", ma_sl+1));
+      BX_DMA_THIS s[ma_sl].mask[0] = value & 0x01; value >>= 1;
+      BX_DMA_THIS s[ma_sl].mask[1] = value & 0x01; value >>= 1;
+      BX_DMA_THIS s[ma_sl].mask[2] = value & 0x01; value >>= 1;
+      BX_DMA_THIS s[ma_sl].mask[3] = value & 0x01;
+      control_HRQ(ma_sl);
+      return;
+      break;
+
+    case 0x81: /* DMA-1 page register, channel 2 */
+    case 0x82: /* DMA-1 page register, channel 3 */
+    case 0x83: /* DMA-1 page register, channel 1 */
+    case 0x87: /* DMA-1 page register, channel 0 */
+      /* address bits A16-A23 for DMA channel */
+      channel = channelindex[address - 0x81];
+      BX_DMA_THIS s[0].chan[channel].page_reg = value;
+      BX_DEBUG(("DMA-1: page register %d = %02x", channel, (unsigned) value));
+      return;
+      break;
+
+    case 0x89: /* DMA-2 page register, channel 2 */
+    case 0x8a: /* DMA-2 page register, channel 3 */
+    case 0x8b: /* DMA-2 page register, channel 1 */
+    case 0x8f: /* DMA-2 page register, channel 0 */
+      /* address bits A16-A23 for DMA channel */
+      channel = channelindex[address - 0x89];
+      BX_DMA_THIS s[1].chan[channel].page_reg = value;
+      BX_DEBUG(("DMA-2: page register %d = %02x", channel + 4, (unsigned) value));
+      return;
+      break;
+
+    case 0x0084:
+    case 0x0085:
+    case 0x0086:
+    case 0x0088:
+    case 0x008c:
+    case 0x008d:
+    case 0x008e:
+      BX_DEBUG(("write: extra page register 0x%04x unsupported", (unsigned) address));
+      return;
+      break;
+
+    default:
+      BX_ERROR(("write ignored: %04xh = %02xh",
+        (unsigned) address, (unsigned) value));
+    }
+}
+
+  void
+bx_dma_c::set_DRQ(unsigned channel, bx_bool val)
+{
+  Bit32u dma_base, dma_roof;
+  bx_bool ma_sl;
+
+  if (channel > 7) {
+    BX_PANIC(("set_DRQ() channel > 7"));
+    return;
+  }
+  ma_sl = (channel > 3);
+  BX_DMA_THIS s[ma_sl].DRQ[channel & 0x03] = val;
+  if (!BX_DMA_THIS s[ma_sl].chan[channel & 0x03].used) {
+    BX_PANIC(("set_DRQ(): channel %d not connected to device", channel));
+    return;
+  }
+  channel &= 0x03;
+  if (!val) {
+    //BX_DEBUG(("bx_dma_c::DRQ(): val == 0"));
+    // clear bit in status reg
+    BX_DMA_THIS s[ma_sl].status_reg &= ~(1 << (channel+4));
+
+    control_HRQ(ma_sl);
+    return;
+  }
+
+#if 0
+  BX_INFO(("mask[%d]: %02x", channel, (unsigned) BX_DMA_THIS s[0].mask[channel]));
+  BX_INFO(("flip_flop: %u", (unsigned) BX_DMA_THIS s[0].flip_flop));
+  BX_INFO(("status_reg: %02x", (unsigned) BX_DMA_THIS s[0].status_reg));
+  BX_INFO(("mode_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.mode_type));
+  BX_INFO(("address_decrement: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.address_decrement));
+  BX_INFO(("autoinit_enable: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.autoinit_enable));
+  BX_INFO(("transfer_type: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].mode.transfer_type));
+  BX_INFO(("base_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_address));
+  BX_INFO(("current_address: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_address));
+  BX_INFO(("base_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].base_count));
+  BX_INFO(("current_count: %04x", (unsigned) BX_DMA_THIS s[0].chan[channel].current_count));
+  BX_INFO(("page_reg: %02x", (unsigned) BX_DMA_THIS s[0].chan[channel].page_reg));
+#endif
+
+  BX_DMA_THIS s[ma_sl].status_reg |= (1 << (channel+4));
+
+  if ( (BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_SINGLE) &&
+       (BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_DEMAND) &&
+       (BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type != DMA_MODE_CASCADE) )
+    BX_PANIC(("set_DRQ: mode_type(%02x) not handled",
+      (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].mode.mode_type));
+
+  dma_base = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
+             (BX_DMA_THIS s[ma_sl].chan[channel].base_address << ma_sl);
+  if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0) {
+    dma_roof = dma_base + (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
+  } else {
+    dma_roof = dma_base - (BX_DMA_THIS s[ma_sl].chan[channel].base_count << ma_sl);
+  }
+  if ( (dma_base & (0x7fff0000 << ma_sl)) != (dma_roof & (0x7fff0000 << ma_sl)) ) {
+    BX_INFO(("dma_base = %08x", (unsigned) dma_base));
+    BX_INFO(("dma_base_count = %08x", (unsigned) BX_DMA_THIS s[ma_sl].chan[channel].base_count));
+    BX_INFO(("dma_roof = %08x", (unsigned) dma_roof));
+    BX_PANIC(("request outside %dk boundary", 64 << ma_sl));
+  }
+
+  control_HRQ(ma_sl);
+}
+
+  void
+bx_dma_c::control_HRQ(bx_bool ma_sl)
+{
+  unsigned channel;
+
+  // deassert HRQ if no DRQ is pending
+  if ((BX_DMA_THIS s[ma_sl].status_reg & 0xf0) == 0) {
+    if (ma_sl) {
+      bx_pc_system.set_HRQ(0);
+    } else {
+      BX_DMA_THIS set_DRQ(4, 0);
+    }
+    return;
+  }
+  // find highest priority channel
+  for (channel=0; channel<4; channel++) {
+    if ( (BX_DMA_THIS s[ma_sl].status_reg & (1 << (channel+4))) &&
+         (BX_DMA_THIS s[ma_sl].mask[channel]==0) ) {
+      if (ma_sl) {
+        // assert Hold ReQuest line to CPU
+        bx_pc_system.set_HRQ(1);
+      } else {
+        // send DRQ to cascade channel of the master
+        BX_DMA_THIS set_DRQ(4, 1);
+      }
+      break;
+    }
+  }
+}
+
+  void
+bx_dma_c::raise_HLDA(void)
+{
+  unsigned channel;
+  Bit32u phy_addr;
+  bx_bool count_expired = 0;
+  bx_bool ma_sl = 0;
+
+  BX_DMA_THIS HLDA = 1;
+  // find highest priority channel
+  for (channel=0; channel<4; channel++) {
+    if ( (BX_DMA_THIS s[1].status_reg & (1 << (channel+4))) &&
+         (BX_DMA_THIS s[1].mask[channel]==0) ) {
+      ma_sl = 1;
+      break;
+      }
+    }
+  if (channel == 0) { // master cascade channel
+    BX_DMA_THIS s[1].DACK[0] = 1;
+    for (channel=0; channel<4; channel++) {
+      if ( (BX_DMA_THIS s[0].status_reg & (1 << (channel+4))) &&
+           (BX_DMA_THIS s[0].mask[channel]==0) ) {
+        ma_sl = 0;
+        break;
+        }
+      }
+    }
+  if (channel >= 4) {
+    // wait till they're unmasked
+    return;
+    }
+
+  //BX_DEBUG(("hlda: OK in response to DRQ(%u)", (unsigned) channel));
+  phy_addr = (BX_DMA_THIS s[ma_sl].chan[channel].page_reg << 16) |
+             (BX_DMA_THIS s[ma_sl].chan[channel].current_address << ma_sl);
+
+  BX_DMA_THIS s[ma_sl].DACK[channel] = 1;
+  // check for expiration of count, so we can signal TC and DACK(n)
+  // at the same time.
+  if (BX_DMA_THIS s[ma_sl].chan[channel].mode.address_decrement==0)
+    BX_DMA_THIS s[ma_sl].chan[channel].current_address++;
+  else
+    BX_DMA_THIS s[ma_sl].chan[channel].current_address--;
+  BX_DMA_THIS s[ma_sl].chan[channel].current_count--;
+  if (BX_DMA_THIS s[ma_sl].chan[channel].current_count == 0xffff) {
+    // count expired, done with transfer
+    // assert TC, deassert HRQ & DACK(n) lines
+    BX_DMA_THIS s[ma_sl].status_reg |= (1 << channel); // hold TC in status reg
+    BX_DMA_THIS TC = 1;
+    count_expired = 1;
+    if (BX_DMA_THIS s[ma_sl].chan[channel].mode.autoinit_enable == 0) {
+      // set mask bit if not in autoinit mode
+      BX_DMA_THIS s[ma_sl].mask[channel] = 1;
+      }
+    else {
+      // count expired, but in autoinit mode
+      // reload count and base address
+      BX_DMA_THIS s[ma_sl].chan[channel].current_address =
+        BX_DMA_THIS s[ma_sl].chan[channel].base_address;
+      BX_DMA_THIS s[ma_sl].chan[channel].current_count =
+        BX_DMA_THIS s[ma_sl].chan[channel].base_count;
+      }
+    }
+
+  Bit8u data_byte;
+  Bit16u data_word;
+
+  if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 1) { // write
+    // DMA controlled xfer of byte from I/O to Memory
+
+    if (!ma_sl) {
+      if (BX_DMA_THIS h[channel].dmaWrite8)
+        BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
+      else
+        BX_PANIC(("no dmaWrite handler for channel %u.", channel));
+
+      BX_MEM_WRITE_PHYSICAL(phy_addr, 1, &data_byte);
+
+      BX_DBG_DMA_REPORT(phy_addr, 1, BX_WRITE, data_byte);
+      }
+    else {
+      if (BX_DMA_THIS h[channel].dmaWrite16)
+        BX_DMA_THIS h[channel].dmaWrite16(&data_word);
+      else
+        BX_PANIC(("no dmaWrite handler for channel %u.", channel));
+
+      BX_MEM_WRITE_PHYSICAL(phy_addr, 2, &data_word);
+
+      BX_DBG_DMA_REPORT(phy_addr, 2, BX_WRITE, data_word);
+      }
+    }
+  else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 2) { // read
+    // DMA controlled xfer of byte from Memory to I/O
+
+    if (!ma_sl) {
+      BX_MEM_READ_PHYSICAL(phy_addr, 1, &data_byte);
+
+      if (BX_DMA_THIS h[channel].dmaRead8)
+        BX_DMA_THIS h[channel].dmaRead8(&data_byte);
+
+      BX_DBG_DMA_REPORT(phy_addr, 1, BX_READ, data_byte);
+      }
+    else {
+      BX_MEM_READ_PHYSICAL(phy_addr, 2, &data_word);
+
+      if (BX_DMA_THIS h[channel].dmaRead16)
+        BX_DMA_THIS h[channel].dmaRead16(&data_word);
+
+      BX_DBG_DMA_REPORT(phy_addr, 2, BX_READ, data_word);
+      }
+    }
+  else if (BX_DMA_THIS s[ma_sl].chan[channel].mode.transfer_type == 0) {
+    // verify
+
+    if (!ma_sl) {
+      if (BX_DMA_THIS h[channel].dmaWrite8)
+        BX_DMA_THIS h[channel].dmaWrite8(&data_byte);
+      else
+        BX_PANIC(("no dmaWrite handler for channel %u.", channel));
+      }
+    else {
+      if (BX_DMA_THIS h[channel].dmaWrite16)
+        BX_DMA_THIS h[channel].dmaWrite16(&data_word);
+      else
+        BX_PANIC(("no dmaWrite handler for channel %u.", channel));
+      }
+    }
+  else {
+    BX_PANIC(("hlda: transfer_type 3 is undefined"));
+    }
+
+  if (count_expired) {
+    BX_DMA_THIS TC = 0;            // clear TC, adapter card already notified
+    BX_DMA_THIS HLDA = 0;
+    bx_pc_system.set_HRQ(0);           // clear HRQ to CPU
+    BX_DMA_THIS s[ma_sl].DACK[channel] = 0; // clear DACK to adapter card
+    if (!ma_sl) {
+      BX_DMA_THIS set_DRQ(4, 0); // clear DRQ to cascade
+      BX_DMA_THIS s[1].DACK[0] = 0; // clear DACK to cascade
+      }
+    }
+}
diff --git a/tools/ioemu/iodev/dma.h b/tools/ioemu/iodev/dma.h
new file mode 100644 (file)
index 0000000..90ac9da
--- /dev/null
@@ -0,0 +1,113 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: dma.h,v 1.15 2003/05/03 07:41:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#ifndef _PCDMA_H
+#define _PCDMA_H
+
+
+#if BX_USE_DMA_SMF
+#  define BX_DMA_SMF  static
+#  define BX_DMA_THIS theDmaDevice->
+#else
+#  define BX_DMA_SMF
+#  define BX_DMA_THIS this->
+#endif
+
+
+
+class bx_dma_c : public bx_dma_stub_c {
+public:
+
+  bx_dma_c();
+  ~bx_dma_c(void);
+
+  virtual void     init(void);
+  virtual void     reset(unsigned type);
+  virtual void     raise_HLDA(void);
+  virtual void     set_DRQ(unsigned channel, bx_bool val);
+  virtual unsigned get_TC(void);
+
+  virtual unsigned registerDMA8Channel(unsigned channel,
+    void (* dmaRead)(Bit8u *data_byte),
+    void (* dmaWrite)(Bit8u *data_byte),
+    const char *name);
+  virtual unsigned registerDMA16Channel(unsigned channel,
+    void (* dmaRead)(Bit16u *data_word),
+    void (* dmaWrite)(Bit16u *data_word),
+    const char *name);
+  virtual unsigned unregisterDMAChannel(unsigned channel);
+
+private:
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_DMA_SMF
+  Bit32u   read( Bit32u   address, unsigned io_len) BX_CPP_AttrRegparmN(2);
+  void     write(Bit32u   address, Bit32u   value, unsigned io_len) BX_CPP_AttrRegparmN(3);
+#endif
+  BX_DMA_SMF void control_HRQ(bx_bool ma_sl);
+  BX_DMA_SMF void reset_controller(unsigned num);
+
+  struct {
+    bx_bool DRQ[4];  // DMA Request
+    bx_bool DACK[4]; // DMA Acknowlege
+
+    bx_bool mask[4];
+    bx_bool flip_flop;
+    Bit8u   status_reg;
+    Bit8u   command_reg;
+    Bit8u   request_reg;
+    Bit8u   temporary_reg;
+    struct {
+      struct {
+        Bit8u mode_type;
+        Bit8u address_decrement;
+        Bit8u autoinit_enable;
+        Bit8u transfer_type;
+        } mode;
+      Bit16u  base_address;
+      Bit16u  current_address;
+      Bit16u  base_count;
+      Bit16u  current_count;
+      Bit8u   page_reg;
+      bx_bool used;
+      } chan[4]; /* DMA channels 0..3 */
+    } s[2];  // state information DMA-1 / DMA-2
+
+  bx_bool HLDA;    // Hold Acknowlege
+  bx_bool TC;      // Terminal Count
+
+  struct {
+    void (* dmaRead8)(Bit8u *data_byte);
+    void (* dmaWrite8)(Bit8u *data_byte);
+    void (* dmaRead16)(Bit16u *data_word);
+    void (* dmaWrite16)(Bit16u *data_word);
+    } h[4]; // DMA read and write handlers
+
+  };
+
+#endif  // #ifndef _PCDMA_H
diff --git a/tools/ioemu/iodev/eth.cc b/tools/ioemu/iodev/eth.cc
new file mode 100644 (file)
index 0000000..d6ee9d2
--- /dev/null
@@ -0,0 +1,194 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth.cc,v 1.16 2003/04/28 13:01:09 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth.cc  - helper code to find and create pktmover classes
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS /* not needed */
+
+eth_locator_c *eth_locator_c::all;
+
+//
+// Each pktmover module has a static locator class that registers
+// here 
+//
+eth_locator_c::eth_locator_c(const char *type)
+{
+  next = all;
+  all  = this;
+  this->type = type;
+}
+
+#ifdef ETH_NULL
+extern class bx_null_locator_c bx_null_match;
+#endif
+#ifdef ETH_FBSD
+extern class bx_fbsd_locator_c bx_fbsd_match;
+#endif
+#ifdef ETH_LINUX
+extern class bx_linux_locator_c bx_linux_match;
+#endif
+#ifdef ETH_WIN32
+extern class bx_win32_locator_c bx_win32_match;
+#endif
+#if HAVE_ETHERTAP
+extern class bx_tap_locator_c bx_tap_match;
+#endif
+#if HAVE_TUNTAP
+extern class bx_tuntap_locator_c bx_tuntap_match;
+#endif
+#ifdef ETH_TEST
+extern bx_test_match;
+#endif
+#ifdef ETH_ARPBACK
+extern class bx_arpback_locator_c bx_arpback_match;
+#endif
+
+//
+// Called by ethernet chip emulations to locate and create a pktmover
+// object
+//
+eth_pktmover_c *
+eth_locator_c::create(const char *type, const char *netif,
+                     const char *macaddr,
+                     eth_rx_handler_t rxh, void *rxarg)
+{
+#ifdef eth_static_constructors
+  for (eth_locator_c *p = all; p != NULL; p = p->next) {
+    if (strcmp(type, p->type) == 0)
+      return (p->allocate(netif, macaddr, rxh, rxarg));
+  }
+#else
+  eth_locator_c *ptr = 0;
+
+#ifdef ETH_ARPBACK
+  {
+    if (!strcmp(type, "arpback"))
+      ptr = (eth_locator_c *) &bx_arpback_match;
+  }
+#endif
+#ifdef ETH_NULL
+  {
+    if (!strcmp(type, "null"))
+      ptr = (eth_locator_c *) &bx_null_match; 
+  }
+#endif
+#ifdef ETH_FBSD
+  {
+    if (!strcmp(type, "fbsd"))    
+      ptr = (eth_locator_c *) &bx_fbsd_match;
+  }
+#endif
+#ifdef ETH_LINUX
+  {
+    if (!strcmp(type, "linux"))    
+      ptr = (eth_locator_c *) &bx_linux_match;
+  }
+#endif
+#if HAVE_TUNTAP
+  {
+    if (!strcmp(type, "tuntap"))    
+      ptr = (eth_locator_c *) &bx_tuntap_match;
+  }
+#endif
+#if HAVE_ETHERTAP
+  {
+    if (!strcmp(type, "tap"))    
+      ptr = (eth_locator_c *) &bx_tap_match;
+  }
+#endif
+#ifdef ETH_WIN32
+  {
+    if(!strcmp(type, "win32"))
+      ptr = (eth_locator_c *) &bx_win32_match;
+  }
+#endif
+#ifdef ETH_TEST
+  {
+    if (!strcmp(type, "test"))    
+      ptr = (eth_locator_c *) &bx_test_match;
+  }
+#endif
+  if (ptr)
+    return (ptr->allocate(netif, macaddr, rxh, rxarg));
+#endif
+
+  return (NULL);
+}
+
+#if (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1)
+
+extern "C" {
+#include <sys/wait.h>
+};
+
+#undef LOG_THIS
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+// This is a utility script used for tuntap or ethertap
+int execute_script( char* scriptname, char* arg1 )
+{
+  int pid,status;
+
+  if (!(pid=fork())) {
+    char filename[BX_PATHNAME_LEN];
+    if ( scriptname[0]=='/' ) {
+      strcpy (filename, scriptname);
+    }
+    else {
+      getcwd (filename, BX_PATHNAME_LEN);
+      strcat (filename, "/");
+      strcat (filename, scriptname);
+    }
+
+    // execute the script
+    BX_INFO(("Executing script '%s %s'",filename,arg1));
+    execle(filename, scriptname, arg1, NULL, NULL);
+
+    // if we get here there has been a problem
+    exit(-1);
+  }
+
+  wait (&status);
+  if (!WIFEXITED(status)) {
+    return -1;
+  }
+  return WEXITSTATUS(status);
+}
+
+#endif // (HAVE_ETHERTAP==1) || (HAVE_TUNTAP==1)
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth.h b/tools/ioemu/iodev/eth.h
new file mode 100644 (file)
index 0000000..8ac8c6f
--- /dev/null
@@ -0,0 +1,76 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth.h,v 1.12 2003/04/26 14:48:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+//  eth.h  - see eth_null.cc for implementation details
+
+typedef void (*eth_rx_handler_t)(void *arg, const void *buf, unsigned len);
+
+int execute_script(char *name, char* arg1);
+
+//
+//  The eth_pktmover class is used by ethernet chip emulations
+// to interface to the outside world. An instance of this
+// would allow frames to be sent to and received from some
+// entity. An example would be the packet filter on a Unix
+// system, an NDIS driver in promisc mode on WinNT, or maybe
+// a simulated network that talks to another process.
+//
+class eth_pktmover_c {
+public:
+  virtual void sendpkt(void *buf, unsigned io_len) = 0;
+  virtual ~eth_pktmover_c (void) {}
+protected:
+  eth_rx_handler_t  rxh;   // receive callback
+  void *rxarg;
+};
+
+
+//
+//  The eth_locator class is used by pktmover classes to register
+// their name. Chip emulations use the static 'create' method
+// to locate and instantiate a pktmover class.
+//
+class eth_locator_c {
+public:
+  static eth_pktmover_c *create(const char *type, const char *netif,
+                               const char *macaddr,
+                               eth_rx_handler_t rxh, 
+                               void *rxarg);
+protected:
+  eth_locator_c(const char *type);
+  virtual eth_pktmover_c *allocate(const char *netif,
+                               const char *macaddr,
+                               eth_rx_handler_t rxh, 
+                               void *rxarg) = 0;
+private:
+  static eth_locator_c *all;
+  eth_locator_c *next;
+  const char *type;
+};
+
diff --git a/tools/ioemu/iodev/eth_arpback.cc b/tools/ioemu/iodev/eth_arpback.cc
new file mode 100644 (file)
index 0000000..0f30711
--- /dev/null
@@ -0,0 +1,214 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_arpback.cc,v 1.11 2002/11/20 19:06:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth_arpback.cc  - basic ethernet packetmover, only responds to ARP
+
+// Various networking docs:
+// http://www.graphcomp.com/info/rfc/
+// rfc0826: arp
+// rfc0903: rarp
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+
+#if BX_NE2K_SUPPORT && defined(ETH_ARPBACK)
+
+#include "crc32.h"
+#include "eth_packetmaker.h"
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+
+//static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
+//static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x00, 0x00, 0x00, 0x00};
+//static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
+//static const Bit8u broadcast_mac[]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
+//static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
+
+#define MAX_FRAME_SIZE 2048
+
+//
+//  Define the class. This is private to this module
+//
+class bx_arpback_pktmover_c : public eth_pktmover_c {
+public:
+  bx_arpback_pktmover_c(const char *netif, const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+private:
+  int rx_timer_index;
+  static void rx_timer_handler(void *);
+  void rx_timer(void);
+  FILE *txlog, *txlog_txt;
+  //Bit8u arpbuf[MAX_FRAME_SIZE];
+  //Bit32u buflen;
+  //bx_bool bufvalid;
+  //CRC_Generator mycrc;
+  eth_ETHmaker packetmaker;
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_arpback_locator_c : public eth_locator_c {
+public:
+  bx_arpback_locator_c(void) : eth_locator_c("arpback") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_arpback_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_arpback_match;
+
+
+//
+// Define the methods for the bx_arpback_pktmover derived class
+//
+
+// the constructor
+bx_arpback_pktmover_c::bx_arpback_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
+                               1, 1, "eth_arpback"); // continuous, active
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+  //bufvalid=0;
+  packetmaker.init();
+#if BX_ETH_NULL_LOGGING
+  // Start the rx poll 
+  // eventually Bryce wants txlog to dump in pcap format so that
+  // tcpdump -r FILE can read it and interpret packets.
+  txlog = fopen ("ne2k-tx.log", "wb");
+  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
+  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
+  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
+  fprintf (txlog_txt, "arpback packetmover readable log file\n");
+  fprintf (txlog_txt, "net IF = %s\n", netif);
+  fprintf (txlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (txlog_txt, "\n--\n");
+  fflush (txlog_txt);
+#endif
+}
+
+void
+bx_arpback_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+  if(io_len<MAX_FRAME_SIZE) {
+    eth_packet barney;
+    memcpy(barney.buf,buf,io_len);
+    barney.len=io_len;
+    if(packetmaker.ishandler(barney)) {
+      packetmaker.sendpacket(barney);
+    }
+    /*
+    if(( (!memcmp(buf, external_mac, 6)) || (!memcmp(buf, broadcast_mac, 6)) )
+       && (!memcmp(((Bit8u *)buf)+12, ethtype_arp, 2)) ) {
+      Bit32u tempcrc;
+      memcpy(arpbuf,buf,io_len); //move to temporary buffer
+      memcpy(arpbuf, arpbuf+6, 6); //set destination to sender
+      memcpy(arpbuf+6, external_mac, 6); //set sender to us
+      memcpy(arpbuf+32, arpbuf+22, 10); //move destination to sender
+      memcpy(arpbuf+22, external_mac, 6); //set sender to us
+      memcpy(arpbuf+28, external_ip, 4); //set sender to us
+      arpbuf[21]=2; //make this a reply and not a request
+      tempcrc=mycrc.get_CRC(arpbuf,io_len);
+      memcpy(arpbuf+io_len, &tempcrc, 4);
+      buflen=io_len;//+4
+      bufvalid=1;
+    }
+    */
+  }
+#if BX_ETH_NULL_LOGGING
+  BX_DEBUG (("sendpkt length %u", io_len));
+  // dump raw bytes to a file, eventually dump in pcap format so that
+  // tcpdump -r FILE can interpret them for us.
+  int n = fwrite (buf, io_len, 1, txlog);
+  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
+  // dump packet in hex into an ascii log file
+  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+  Bit8u *charbuf = (Bit8u *)buf;
+  for (n=0; n<io_len; n++) {
+    if (((n % 16) == 0) && n>0)
+      fprintf (txlog_txt, "\n");
+    fprintf (txlog_txt, "%02x ", charbuf[n]);
+  }
+  fprintf (txlog_txt, "\n--\n");
+  // flush log so that we see the packets as they arrive w/o buffering
+  fflush (txlog);
+  fflush (txlog_txt);
+#endif
+}
+
+void bx_arpback_pktmover_c::rx_timer_handler (void * this_ptr)
+{
+#if BX_ETH_NULL_LOGGING
+  BX_DEBUG (("rx_timer_handler"));
+#endif
+  bx_arpback_pktmover_c *class_ptr = ((bx_arpback_pktmover_c *)this_ptr);
+
+  class_ptr->rx_timer();
+}
+
+void bx_arpback_pktmover_c::rx_timer (void)
+{
+  int nbytes = 0;
+  struct bpf_hdr *bhdr;
+  eth_packet rubble;
+  
+  if(packetmaker.getpacket(rubble)) {
+    //bufvalid=0;
+    void * buf=rubble.buf;
+    unsigned io_len=rubble.len;
+    Bit32u n;
+    fprintf (txlog_txt, "NE2K receiving a packet, length %u\n", io_len);
+    Bit8u *charbuf = (Bit8u *)buf;
+    for (n=0; n<io_len; n++) {
+      if (((n % 16) == 0) && n>0)
+       fprintf (txlog_txt, "\n");
+      fprintf (txlog_txt, "%02x ", charbuf[n]);
+    }
+    fprintf (txlog_txt, "\n--\n");
+    fflush (txlog_txt);
+
+    (*rxh)(rxarg, buf, io_len);
+  }
+}
+
+#endif /* if BX_NE2K_SUPPORT && defined(ETH_ARPBACK) */
+
diff --git a/tools/ioemu/iodev/eth_fbsd.cc b/tools/ioemu/iodev/eth_fbsd.cc
new file mode 100644 (file)
index 0000000..0c24b9b
--- /dev/null
@@ -0,0 +1,385 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_fbsd.cc,v 1.26 2002/11/20 19:06:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+// eth_fbsd.cc - A FreeBSD packet filter implementation of
+// an ethernet pktmover. There are some problems and limitations
+// with FreeBSD:
+//   - the source address of the frame is overwritten by
+//    the hosts's source address. This causes problems with
+//    learning bridges - since they cannot determine where
+//    BOCHS 'is', they broadcast the frame to all ports.
+//   - packets cannot be sent from BOCHS to the host
+//   - TCP performance seems to be abysmal; I think this is
+//     a timing problem somewhere.
+//   - I haven't handled the case where multiple frames arrive
+//     in a single BPF read. 
+//
+//   The /dev/bpf* devices need to be set up with the appropriate
+//  permissions for this to work.
+//
+//   The config line in .bochsrc should look something like:
+//
+//  ne2k: ioaddr=0x280, irq=9, mac=00:a:b:c:1:2, ethmod=fbsd, ethdev=fxp0
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT && defined(ETH_FBSD)
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+extern "C" {
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/bpf.h>
+#include <errno.h>
+};
+
+#define BX_BPF_POLL  1000    // Poll for a frame every 250 usecs
+
+#define BX_BPF_BUFSIZ 2048   // enough for an ether frame + bpf hdr
+
+#define BX_BPF_INSNSIZ  8    // number of bpf insns
+
+// template filter for a unicast mac address and all 
+// multicast/broadcast frames
+static const struct bpf_insn macfilter[] = {
+    BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                  // A <- P[2:4]
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),  // if A != 0xaaaaaaa GOTO LABEL-1
+    BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),                  // A <- P[0:2]
+    BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),  // if A == 0xaaaa GOTO ACCEPT
+    // LABEL-1
+    BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),                  // A <- P[0:1]
+    BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),       // if !(A & 1) GOTO LABEL-REJECT
+    // LABEL-ACCEPT
+    BPF_STMT(BPF_RET, 1514),                            // Accept packet
+    // LABEL-REJECT
+    BPF_STMT(BPF_RET, 0),                               // Reject packet
+};
+
+// template filter for all frames
+static const struct bpf_insn promiscfilter[] = {
+  BPF_STMT(BPF_RET, 1514)
+};
+
+//
+//  Define the class. This is private to this module
+//
+class bx_fbsd_pktmover_c : public eth_pktmover_c {
+public:
+  bx_fbsd_pktmover_c(const char *netif, 
+                    const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+
+private:
+  char *fbsd_macaddr[6];
+  int bpf_fd;
+  static void rx_timer_handler(void *);
+  void rx_timer(void);
+  int rx_timer_index;
+  struct bpf_insn filter[BX_BPF_INSNSIZ];
+  FILE *ne2klog, *ne2klog_txt;
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_fbsd_locator_c : public eth_locator_c {
+public:
+  bx_fbsd_locator_c(void) : eth_locator_c("fbsd") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, 
+                          const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_fbsd_match;
+
+
+//
+// Define the methods for the bx_fbsd_pktmover derived class
+//
+
+// the constructor
+//
+// Open a bpf file descriptor, and attempt to bind to
+// the specified netif (Replicates libpcap open code)
+//
+bx_fbsd_pktmover_c::bx_fbsd_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+  char device[sizeof "/dev/bpf000"];
+  int tmpfd;
+  int n = 0;
+  struct ifreq ifr;
+  struct bpf_version bv;
+  struct bpf_program bp;
+  u_int v;
+
+  memcpy(fbsd_macaddr, macaddr, 6);
+
+  do {
+    (void)sprintf(device, "/dev/bpf%d", n++);
+    this->bpf_fd = open(device, O_RDWR);
+       BX_DEBUG(("tried %s, returned %d (%s)",device,this->bpf_fd,strerror(errno)));
+       if(errno == EACCES)
+               break;
+  } while (this->bpf_fd == -1);
+  
+  if (this->bpf_fd == -1) {
+    BX_PANIC(("eth_freebsd: could not open packet filter: %s", strerror(errno)));
+    return;
+  }
+
+  if (ioctl(this->bpf_fd, BIOCVERSION, (caddr_t)&bv) < 0) {
+    BX_PANIC(("eth_freebsd: could not retrieve bpf version"));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+  if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION) {
+    BX_PANIC(("eth_freebsd: bpf version mismatch between compilation and runtime"));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  // Set buffer size
+  v = BX_BPF_BUFSIZ;
+  if (ioctl(this->bpf_fd, BIOCSBLEN, (caddr_t)&v) < 0) {
+    BX_PANIC(("eth_freebsd: could not set buffer size: %s", strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  (void)strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
+  if (ioctl(this->bpf_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+    BX_PANIC(("eth_freebsd: could not enable interface '%s': %s", netif, strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd == -1;
+  }
+  
+  // Verify that the device is an ethernet.
+  if (ioctl(this->bpf_fd, BIOCGDLT, (caddr_t)&v) < 0) {
+    BX_PANIC(("eth_freebsd: could not retrieve datalink type: %s", strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+  if (v != DLT_EN10MB) {
+    BX_PANIC(("eth_freebsd: incorrect datalink type %d, expected 10mb ethernet", v));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  // Put the device into promisc mode. This could be optimised
+  // to filter on a MAC address, broadcast, and all-multi,
+  // but this will do for now.
+  //
+  if (ioctl(this->bpf_fd, BIOCPROMISC, NULL) < 0) {
+    BX_PANIC(("eth_freebsd: could not enable promisc mode: %s", strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  // Set up non-blocking i/o
+  v = 1;
+  if (ioctl(this->bpf_fd, FIONBIO, &v) < 0) {
+    BX_PANIC(("eth_freebsd: could not enable non-blocking i/o: %s", strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  // Install a filter
+#ifdef notdef
+  memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
+  bp.bf_len   = 1;
+#else
+  memcpy(&this->filter, macfilter, sizeof(macfilter));
+  this->filter[1].k =
+      (macaddr[2] & 0xff) << 24 |
+    (macaddr[3] & 0xff) << 16 |
+    (macaddr[4] & 0xff) << 8  |
+    (macaddr[5] & 0xff);
+  this->filter[3].k =
+      (macaddr[0] & 0xff) << 8 |
+    (macaddr[1] & 0xff);
+  bp.bf_len   = 8;
+#endif
+  bp.bf_insns = &this->filter[0];
+  if (ioctl(this->bpf_fd, BIOCSETF, &bp) < 0) {
+    BX_PANIC(("eth_freebsd: could not set filter: %s", strerror(errno)));
+    close(this->bpf_fd);
+    this->bpf_fd = -1;
+    return;
+  }
+
+  // Start the rx poll 
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, BX_BPF_POLL,
+                               1, 1, "eth_fbsd"); // continuous, active
+
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+
+#if BX_ETH_FBSD_LOGGING
+  // eventually Bryce wants ne2klog to dump in pcap format so that
+  // tcpdump -r FILE can read it and interpret packets.
+  ne2klog = fopen ("ne2k.raw", "wb");
+  if (!ne2klog) BX_PANIC (("open ne2k-tx.log failed"));
+  ne2klog_txt = fopen ("ne2k.txt", "wb");
+  if (!ne2klog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
+  fprintf (ne2klog_txt, "null packetmover readable log file\n");
+  fprintf (ne2klog_txt, "net IF = %s\n", netif);
+  fprintf (ne2klog_txt, "MAC address = ");
+  for (int i=0; i<6; i++)
+    fprintf (ne2klog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (ne2klog_txt, "\n--\n");
+  fflush (ne2klog_txt);
+#endif
+}
+
+// the output routine - called with pre-formatted ethernet frame.
+void
+bx_fbsd_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+#if BX_ETH_FBSD_LOGGING
+  BX_DEBUG (("sendpkt length %u", io_len));
+  // dump raw bytes to a file, eventually dump in pcap format so that
+  // tcpdump -r FILE can interpret them for us.
+  int n = fwrite (buf, io_len, 1, ne2klog);
+  if (n != 1) BX_ERROR (("fwrite to ne2klog failed", io_len));
+  // dump packet in hex into an ascii log file
+  fprintf (ne2klog_txt, "NE2K TX packet, length %u\n", io_len);
+  Bit8u *charbuf = (Bit8u *)buf;
+  for (n=0; n<io_len; n++) {
+    if (((n % 16) == 0) && n>0)
+      fprintf (ne2klog_txt, "\n");
+    fprintf (ne2klog_txt, "%02x ", charbuf[n]);
+  }
+  fprintf (ne2klog_txt, "\n--\n");
+  // flush log so that we see the packets as they arrive w/o buffering
+  fflush (ne2klog);
+  fflush (ne2klog_txt);
+#endif
+  int status;
+
+  if (this->bpf_fd != -1)
+    status = write(this->bpf_fd, buf, io_len);
+}
+
+// The receive poll process
+void
+bx_fbsd_pktmover_c::rx_timer_handler(void *this_ptr)
+{
+  bx_fbsd_pktmover_c *class_ptr = (bx_fbsd_pktmover_c *) this_ptr;
+
+  class_ptr->rx_timer();
+}
+
+
+void
+bx_fbsd_pktmover_c::rx_timer(void)
+{
+  int nbytes = 0;
+    unsigned char rxbuf[BX_BPF_BUFSIZ]; 
+  struct bpf_hdr *bhdr;
+    struct bpf_stat bstat;
+    static struct bpf_stat previous_bstat;
+    int counter = 10;
+#define phdr ((unsigned char*)bhdr)
+
+    bhdr = (struct bpf_hdr *) rxbuf;
+  nbytes = read(this->bpf_fd, rxbuf, sizeof(rxbuf));
+
+    while (phdr < (rxbuf + nbytes)) {
+       if (ioctl(this->bpf_fd, BIOCGSTATS, &bstat) < 0) {
+           BX_PANIC(("eth_freebsd: could not stat filter: %s", strerror(errno)));
+       }
+       if (bstat.bs_drop > previous_bstat.bs_drop) {
+           BX_INFO (("eth_freebsd: %d packets dropped by the kernel.",
+                     bstat.bs_drop - previous_bstat.bs_drop));
+       }
+       previous_bstat = bstat;
+       if (bhdr->bh_caplen < 20 || bhdr->bh_caplen > 1514) {
+           BX_ERROR(("eth_freebsd: received too weird packet length: %d", bhdr->bh_caplen));
+       }
+
+    // filter out packets sourced from this node
+       if (memcmp(bhdr + bhdr->bh_hdrlen + 6, this->fbsd_macaddr, 6)) {
+           (*rxh)(rxarg, phdr + bhdr->bh_hdrlen, bhdr->bh_caplen);
+    }
+       
+#if BX_ETH_FBSD_LOGGING
+  /// hey wait there is no receive data with a NULL ethernet, is there....
+    BX_DEBUG (("receive packet length %u", nbytes));
+    // dump raw bytes to a file, eventually dump in pcap format so that
+    // tcpdump -r FILE can interpret them for us.
+       if (1 != fwrite (bhdr, bhdr->bh_caplen, 1, ne2klog)) {
+           BX_PANIC (("fwrite to ne2klog failed: %s", strerror(errno)));
+       }
+    // dump packet in hex into an ascii log file
+       fprintf (this->ne2klog_txt, "NE2K RX packet, length %u\n", bhdr->bh_caplen);
+    Bit8u *charrxbuf = (Bit8u *)rxbuf;
+       int n;
+       for (n=0; n<bhdr->bh_caplen; n++) {
+      if (((n % 16) == 0) && n>0)
+       fprintf (this->ne2klog_txt, "\n");
+           fprintf (this->ne2klog_txt, "%02x ", phdr[n]);
+    }
+    fprintf (this->ne2klog_txt, "\n--\n");
+    // flush log so that we see the packets as they arrive w/o buffering
+    fflush (this->ne2klog);
+    fflush (this->ne2klog_txt);
+#endif
+
+       // Advance bhdr and phdr pointers to next packet
+       bhdr = (struct bpf_hdr*) ((char*) bhdr + BPF_WORDALIGN(bhdr->bh_hdrlen + bhdr->bh_caplen));
+  }  
+}
+
+#endif /* if BX_NE2K_SUPPORT && defined(ETH_FBSD) */
+
diff --git a/tools/ioemu/iodev/eth_linux.cc b/tools/ioemu/iodev/eth_linux.cc
new file mode 100644 (file)
index 0000000..ec5f1fe
--- /dev/null
@@ -0,0 +1,286 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_linux.cc,v 1.14 2003/02/16 19:35:57 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+// eth_linux.cc - A Linux socket filter adaptation of the FreeBSD BPF driver
+// <splite@purdue.edu> 21 June 2001
+//
+// Problems and limitations:
+//   - packets cannot be sent from BOCHS to the host
+//   - Linux kernel sometimes gets network watchdog timeouts under emulation
+//   - author doesn't know C++
+//
+//   The config line in .bochsrc should look something like:
+//
+//  ne2k: ioaddr=0x280, irq=10, mac=00:a:b:c:1:2, ethmod=linux, ethdev=eth0
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT && defined (ETH_LINUX)
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+extern "C" {
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netpacket/packet.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <linux/types.h>
+#include <linux/filter.h>
+};
+
+#define BX_PACKET_POLL  1000    // Poll for a frame every 1000 usecs
+
+#define BX_PACKET_BUFSIZ 2048  // Enough for an ether frame
+
+// template filter for a unicast mac address and all
+// multicast/broadcast frames
+static const struct sock_filter macfilter[] = {
+  BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
+  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
+  BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
+  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
+  BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
+  BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
+  BPF_STMT(BPF_RET, 1514),
+  BPF_STMT(BPF_RET, 0),
+};
+#define BX_LSF_ICNT 8    // number of lsf instructions in macfilter
+
+#if 0
+// template filter for all frames
+static const struct sock_filter promiscfilter[] = {
+  BPF_STMT(BPF_RET, 1514)
+};
+#endif
+
+//
+//  Define the class. This is private to this module
+//
+class bx_linux_pktmover_c : public eth_pktmover_c {
+public:
+  bx_linux_pktmover_c(const char *netif, 
+                    const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+
+private:
+  unsigned char *linux_macaddr[6];
+  int fd;
+  int ifindex;
+  static void rx_timer_handler(void *);
+  void rx_timer(void);
+  int rx_timer_index;
+  struct sock_filter filter[BX_LSF_ICNT];
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_linux_locator_c : public eth_locator_c {
+public:
+  bx_linux_locator_c(void) : eth_locator_c("linux") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, 
+                          const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_linux_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_linux_match;
+
+
+//
+// Define the methods for the bx_linux_pktmover derived class
+//
+
+// the constructor
+//
+bx_linux_pktmover_c::bx_linux_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+  struct sockaddr_ll sll;
+  struct packet_mreq mr;
+  struct ifreq ifr;
+  struct sock_fprog fp;
+
+  memcpy(linux_macaddr, macaddr, 6);
+
+  // Open packet socket
+  //
+  if ((this->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
+    if (errno == EACCES)
+      BX_PANIC(("eth_linux: must be root or have CAP_NET_RAW capability to open socket"));
+    else
+      BX_PANIC(("eth_linux: could not open socket: %s", strerror(errno)));
+    this->fd = -1;
+    return;
+  }
+  
+  // Translate interface name to index
+  //
+  memset(&ifr, 0, sizeof(ifr));
+  strcpy(ifr.ifr_name, netif);
+  if (ioctl(this->fd, SIOCGIFINDEX, &ifr) == -1) {
+    BX_PANIC(("eth_linux: could not get index for interface '%s'\n", netif));
+    close(fd);
+    this->fd = -1;
+    return;
+  }
+  this->ifindex = ifr.ifr_ifindex;
+
+
+  // Bind to given interface
+  //
+  memset(&sll, 0, sizeof(sll));
+  sll.sll_family = AF_PACKET;
+  sll.sll_ifindex = this->ifindex;
+  if (bind(fd, (struct sockaddr *)&sll, (socklen_t)sizeof(sll)) == -1) {
+    BX_PANIC(("eth_linux: could not bind to interface '%s': %s\n", netif, strerror(errno)));
+    close(fd);
+    this->fd = -1;
+    return;
+  }
+
+  // Put the device into promisc mode.
+  //
+  memset(&mr, 0, sizeof(mr));
+  mr.mr_ifindex = this->ifindex;
+  mr.mr_type = PACKET_MR_PROMISC;
+  if (setsockopt(this->fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, (void *)&mr, (socklen_t)sizeof(mr)) == -1) {
+    BX_PANIC(("eth_linux: could not enable promisc mode: %s\n", strerror(errno)));
+    close(this->fd);
+    this->fd = -1;
+    return;
+  }
+
+  // Set up non-blocking i/o
+  if (fcntl(this->fd, F_SETFL, O_NONBLOCK) == -1) {
+    BX_PANIC(("eth_linux: could not set non-blocking i/o on socket"));
+    close(this->fd);
+    this->fd = -1;
+    return;
+  }
+
+  // Install a filter
+#ifdef notdef
+  memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
+  fp.len   = 1;
+#endif
+  memcpy(&this->filter, macfilter, sizeof(macfilter));
+  this->filter[1].k = (macaddr[2] & 0xff) << 24 | (macaddr[3] & 0xff) << 16 |
+    (macaddr[4] & 0xff) << 8  | (macaddr[5] & 0xff);
+  this->filter[3].k = (macaddr[0] & 0xff) << 8 | (macaddr[1] & 0xff);
+  fp.len = BX_LSF_ICNT;
+  fp.filter = this->filter;
+  BX_INFO(("eth_linux: fp.len=%d fp.filter=%x", fp.len, (unsigned) fp.filter));
+  if (setsockopt(this->fd, SOL_SOCKET, SO_ATTACH_FILTER, &fp, sizeof(fp)) < 0) {
+    BX_PANIC(("eth_linux: could not set socket filter: %s", strerror(errno)));
+    close(this->fd);
+    this->fd = -1;
+    return;
+  }
+
+  // Start the rx poll 
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, BX_PACKET_POLL,
+                               1, 1, "eth_linux"); // continuous, active
+
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+  BX_INFO(("eth_linux: enabled NE2K emulation on interface %s", netif));
+}
+
+// the output routine - called with pre-formatted ethernet frame.
+void
+bx_linux_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+  int status;
+
+  if (this->fd != -1) {
+    status = write(this->fd, buf, io_len);
+    if (status == -1)
+      BX_INFO(("eth_linux: write failed: %s", strerror(errno)));
+  }
+}
+
+// The receive poll process
+void
+bx_linux_pktmover_c::rx_timer_handler(void *this_ptr)
+{
+  bx_linux_pktmover_c *class_ptr = (bx_linux_pktmover_c *) this_ptr;
+
+  class_ptr->rx_timer();
+}
+
+void
+bx_linux_pktmover_c::rx_timer(void)
+{
+  int nbytes = 0;
+  Bit8u rxbuf[BX_PACKET_BUFSIZ]; 
+  struct sockaddr_ll sll;
+  socklen_t fromlen;
+//static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+  if (this->fd == -1)
+    return;
+
+  fromlen = sizeof(sll);
+  nbytes = recvfrom(this->fd, rxbuf, sizeof(rxbuf), 0, (struct sockaddr *)&sll, &fromlen);
+
+  if (nbytes == -1) {
+    if (errno != EAGAIN)
+      BX_INFO(("eth_linux: error receiving packet: %s\n", strerror(errno)));
+    return;
+  }
+
+  // this should be done with LSF someday
+  // filter out packets sourced by us
+  if (memcmp(sll.sll_addr, this->linux_macaddr, 6) == 0)
+    return;
+  // let through broadcast, multicast, and our mac address
+//  if ((memcmp(rxbuf, bcast_addr, 6) == 0) || (memcmp(rxbuf, this->linux_macaddr, 6) == 0) || rxbuf[0] & 0x01) {
+    BX_DEBUG(("eth_linux: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
+    (*rxh)(rxarg, rxbuf, nbytes);
+//  }
+}
+#endif /* if BX_NE2K_SUPPORT && defined ETH_LINUX */
diff --git a/tools/ioemu/iodev/eth_null.cc b/tools/ioemu/iodev/eth_null.cc
new file mode 100644 (file)
index 0000000..1116279
--- /dev/null
@@ -0,0 +1,164 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_null.cc,v 1.13 2002/11/20 19:06:23 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth_null.cc  - skeleton code for an ethernet pktmover
+
+// Various networking docs:
+// http://www.graphcomp.com/info/rfc/
+// rfc0826: arp
+// rfc0903: rarp
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+
+//
+//  Define the class. This is private to this module
+//
+class bx_null_pktmover_c : public eth_pktmover_c {
+public:
+  bx_null_pktmover_c(const char *netif, const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+private:
+  int rx_timer_index;
+  static void rx_timer_handler(void *);
+  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_null_locator_c : public eth_locator_c {
+public:
+  bx_null_locator_c(void) : eth_locator_c("null") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_null_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_null_match;
+
+
+//
+// Define the methods for the bx_null_pktmover derived class
+//
+
+// the constructor
+bx_null_pktmover_c::bx_null_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+#if BX_ETH_NULL_LOGGING
+  // Start the rx poll 
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
+                               1, 1, "eth_null"); // continuous, active
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+  // eventually Bryce wants txlog to dump in pcap format so that
+  // tcpdump -r FILE can read it and interpret packets.
+  txlog = fopen ("ne2k-tx.log", "wb");
+  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
+  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
+  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
+  fprintf (txlog_txt, "null packetmover readable log file\n");
+  fprintf (txlog_txt, "net IF = %s\n", netif);
+  fprintf (txlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (txlog_txt, "\n--\n");
+  fflush (txlog_txt);
+#endif
+}
+
+void
+bx_null_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+#if BX_ETH_NULL_LOGGING
+  BX_DEBUG (("sendpkt length %u", io_len));
+  // dump raw bytes to a file, eventually dump in pcap format so that
+  // tcpdump -r FILE can interpret them for us.
+  unsigned int n = fwrite (buf, io_len, 1, txlog);
+  if (n != 1) BX_ERROR (("fwrite to txlog failed, io_len = %u", io_len));
+  // dump packet in hex into an ascii log file
+  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+  Bit8u *charbuf = (Bit8u *)buf;
+  for (n=0; n<io_len; n++) {
+    if (((n % 16) == 0) && n>0)
+      fprintf (txlog_txt, "\n");
+    fprintf (txlog_txt, "%02x ", charbuf[n]);
+  }
+  fprintf (txlog_txt, "\n--\n");
+  // flush log so that we see the packets as they arrive w/o buffering
+  fflush (txlog);
+  fflush (txlog_txt);
+#endif
+}
+
+void bx_null_pktmover_c::rx_timer_handler (void *this_ptr)
+{
+#if BX_ETH_NULL_LOGGING
+  /// hey wait there is no receive data with a NULL ethernet, is there....
+
+  int io_len = 0;
+  Bit8u buf[1];
+  bx_null_pktmover_c *class_ptr = (bx_null_pktmover_c *) this_ptr;
+  if (io_len > 0) {
+    BX_DEBUG (("receive packet length %u", io_len));
+    // dump raw bytes to a file, eventually dump in pcap format so that
+    // tcpdump -r FILE can interpret them for us.
+    int n = fwrite (buf, io_len, 1, class_ptr->rxlog);
+    if (n != 1) BX_ERROR (("fwrite to rxlog failed, io_len = %u", io_len));
+    // dump packet in hex into an ascii log file
+    fprintf (class_ptr->rxlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+    Bit8u *charbuf = (Bit8u *)buf;
+    for (n=0; n<io_len; n++) {
+      if (((n % 16) == 0) && n>0)
+       fprintf (class_ptr->rxlog_txt, "\n");
+      fprintf (class_ptr->rxlog_txt, "%02x ", charbuf[n]);
+    }
+    fprintf (class_ptr->rxlog_txt, "\n--\n");
+    // flush log so that we see the packets as they arrive w/o buffering
+    fflush (class_ptr->rxlog);
+    fflush (class_ptr->rxlog_txt);
+  }
+#endif
+}
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth_packetmaker.cc b/tools/ioemu/iodev/eth_packetmaker.cc
new file mode 100644 (file)
index 0000000..5ed5e47
--- /dev/null
@@ -0,0 +1,184 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_packetmaker.cc,v 1.8 2002/11/20 19:06:23 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+
+#if BX_NE2K_SUPPORT && defined(ETH_ARPBACK)
+
+#include "eth_packetmaker.h"
+
+
+bx_bool sendable(const eth_packet& outpacket) {
+  //FINISH ME!
+}
+
+Bit32u eth_IPmaker::datalen(const eth_packet& outpacket) {
+  Bit32u out;
+  out=((outpacket.buf[16]<<8)+outpacket.buf[17])-(4*(0xF & outpacket.buf[14]));
+  return out;
+}
+
+const Bit8u * eth_IPmaker::datagram(const eth_packet& outpacket) {
+  const Bit8u * out;
+  out=outpacket.buf+14+(4*(0xF & outpacket.buf[14]));
+  return out;
+}
+
+Bit32u eth_IPmaker::build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen) {
+  Bit32u temp;
+  Bit32u i;
+  memcpy(pending.buf,internal_mac,6);
+  memcpy(pending.buf+6,external_mac,6);
+  memcpy(pending.buf+12,ethtype_ip,2);
+  pending.buf[14]=0x45;
+  pending.buf[15]=0;
+  temp=datalen+20;
+  pending.buf[16]=(temp>>8) & 0xFF;
+  pending.buf[17]=temp & 0xFF;
+  pending.buf[18]=0;
+  pending.buf[19]=0;
+  pending.buf[20]=0;
+  pending.buf[21]=0;
+  pending.buf[22]=30;
+  pending.buf[23]=protocol;
+  pending.buf[24]=0;
+  pending.buf[25]=0;
+  pending.buf[26]=(source>>24) & 0xFF;
+  pending.buf[27]=(source>>16) & 0xFF;
+  pending.buf[28]=(source>>8) & 0xFF;
+  pending.buf[29]=(source) & 0xFF;
+  pending.buf[30]=(dest>>24) & 0xFF;
+  pending.buf[31]=(dest>>16) & 0xFF;
+  pending.buf[32]=(dest>>8) & 0xFF;
+  pending.buf[33]=(dest) & 0xFF;
+  //Compute Checksum
+  temp=0;
+  for(i=14;i<34;i=i+2) {
+    Bit32u addee=pending.buf[i];
+    addee=(addee<<8) & pending.buf[i+1];
+    temp=temp+addee;
+  }
+  temp=(temp>>16)+(temp&0xFFFF);
+  temp=(temp>>16)+(temp&0xFFFF);
+  pending.buf[24]=~(Bit8u)((temp>>8) & 0xFF);
+  pending.buf[25]=~(Bit8u)(temp & 0xFF);
+  return(34);
+}
+
+Bit8u eth_IPmaker::protocol(const eth_packet& outpacket) {
+  Bit8u out;
+  out=0xFF & *(outpacket.buf+23);
+}
+
+Bit32u eth_IPmaker::source(const eth_packet& outpacket) {
+  Bit32u out;
+  out=0xFF & *(outpacket.buf+26);
+  out=(out<<8) | (0xFF & *(outpacket.buf+27));
+  out=(out<<8) | (0xFF & *(outpacket.buf+28));
+  out=(out<<8) | (0xFF & *(outpacket.buf+29));
+  return out;
+}
+
+Bit32u eth_IPmaker::destination(const eth_packet& outpacket) {
+  Bit32u out;
+  out=0xFF & *(outpacket.buf+30);
+  out=(out<<8) | (0xFF & *(outpacket.buf+31));
+  out=(out<<8) | (0xFF & *(outpacket.buf+32));
+  out=(out<<8) | (0xFF & *(outpacket.buf+33));
+  return out;
+}
+
+void eth_IPmaker::init(void) {
+  is_pending=0;
+}
+
+void
+eth_ETHmaker::init(void) {
+  arper.init();
+}
+
+bx_bool
+eth_ETHmaker::getpacket(eth_packet& inpacket) {
+  return arper.getpacket(inpacket);
+}
+
+bx_bool
+eth_ETHmaker::ishandler(const eth_packet& outpacket) {
+  if((outpacket.len>=60) &&
+     ( (!memcmp(outpacket.buf, external_mac, 6))
+       || (!memcmp(outpacket.buf, broadcast_mac, 6)) ) &&
+     ( (!memcmp(outpacket.buf+12, ethtype_arp, 2)) ||
+       (!memcmp(outpacket.buf+12, ethtype_ip, 2)) ) &&
+     (outpacket.len<PACKET_BUF_SIZE)
+     ) {
+    return 1;
+  }
+  return 0;  
+}
+
+bx_bool
+eth_ETHmaker::sendpacket(const eth_packet& outpacket) {
+  return arper.sendpacket(outpacket);
+}
+
+
+
+void
+eth_ARPmaker::init(void) {
+  is_pending=0;
+  pending.len=0;
+}
+
+bx_bool
+eth_ARPmaker::getpacket(eth_packet& inpacket) {
+  if(is_pending) {
+    memcpy(inpacket.buf,pending.buf,pending.len);
+    inpacket.len=pending.len;
+    is_pending=0;
+    return 1;
+  }
+  return 0;
+}
+
+bx_bool
+eth_ARPmaker::ishandler(const eth_packet& outpacket) {
+  if((outpacket.len>=60) &&
+     (!memcmp(outpacket.buf+12, ethtype_arp, 2)) &&
+     (outpacket.len<PACKET_BUF_SIZE) &&
+     ( (!memcmp(outpacket.buf, external_mac, 6))
+       || (!memcmp(outpacket.buf, broadcast_mac, 6)) ) &&
+     (!memcmp(outpacket.buf+38, external_ip, 4))
+     ) {
+    return 1;
+  }
+  return 0;
+}
+
+bx_bool
+eth_ARPmaker::sendpacket(const eth_packet& outpacket) {
+  if(is_pending || !ishandler(outpacket)) {
+    return 0;
+  } else {
+    Bit32u tempcrc;
+    memcpy(pending.buf,outpacket.buf,outpacket.len); //move to temporary buffer
+    memcpy(pending.buf, pending.buf+6, 6); //set destination to sender
+    memcpy(pending.buf+6, external_mac, 6); //set sender to us
+    memcpy(pending.buf+32, pending.buf+22, 10); //move destination to sender
+    memcpy(pending.buf+22, external_mac, 6); //set sender to us
+    memcpy(pending.buf+28, external_ip, 4); //set sender to us
+    pending.buf[21]=2; //make this a reply and not a request
+    //tempcrc=mycrc.get_CRC(pending.buf,len);
+    //memcpy(pending.buf+len, &tempcrc, 4);
+    pending.len=outpacket.len; //+4
+    is_pending=1;
+    return 1;
+  }
+}
+
+#endif /* if BX_NE2K_SUPPORT && defined(ETH_ARPBACK) */
diff --git a/tools/ioemu/iodev/eth_packetmaker.h b/tools/ioemu/iodev/eth_packetmaker.h
new file mode 100644 (file)
index 0000000..d442325
--- /dev/null
@@ -0,0 +1,135 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_packetmaker.h,v 1.6 2002/10/25 11:44:39 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+
+#ifndef _ETH_PACKETMAKER_H_
+#define _ETH_PACKETMAKER_H_
+
+#include "../config.h"
+
+#ifdef ETH_ARPBACK
+
+#define PACKET_BUF_SIZE 2048
+static const Bit8u internal_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
+static const Bit8u external_mac[]={0xB0, 0xC4, 0x20, 0x20, 0x00, 0x00, 0x00};
+static const Bit8u external_ip[]={ 192, 168, 0, 2, 0x00 };
+static const Bit8u broadcast_mac[]={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
+static const Bit8u ethtype_arp[]={0x08, 0x06, 0x00};
+static const Bit8u ethtype_ip[]={0x08, 0x00, 0x00};
+static const Bit8u prot_udp=17;
+static const Bit8u prot_tcp=6;
+
+
+class eth_packet {
+public:
+  Bit8u buf[PACKET_BUF_SIZE];
+  Bit32u len;
+};
+
+
+class eth_packetmaker {
+public:
+  virtual bx_bool getpacket(eth_packet& inpacket) = 0;
+  virtual bx_bool ishandler(const eth_packet& outpacket) = 0;
+  virtual bx_bool sendpacket(const eth_packet& outpacket) = 0;
+};
+
+
+class eth_ARPmaker : public eth_packetmaker {
+public:
+  void init(void);
+  bx_bool ishandler(const eth_packet& outpacket);
+  bx_bool sendpacket(const eth_packet& outpacket);
+  bx_bool getpacket(eth_packet& inpacket);
+private:
+  eth_packet pending;
+  bx_bool is_pending;
+};
+
+
+class eth_IPmaker : eth_packetmaker {
+public:
+  void init(void);
+  virtual bx_bool ishandler(const eth_packet& outpacket)=0;
+  virtual bx_bool sendpacket(const eth_packet& outpacket)=0;
+  virtual bx_bool getpacket(eth_packet& inpacket)=0;
+
+protected:
+  bx_bool sendable(const eth_packet& outpacket);
+
+  Bit32u source(const eth_packet& outpacket);
+  Bit32u destination(const eth_packet& outpacket);
+  Bit8u protocol(const eth_packet& outpacket);
+
+  const Bit8u * datagram(const eth_packet& outpacket);
+  Bit32u datalen(const eth_packet& outpacket);
+
+  //Build a header in pending, return header length in bytes.
+  Bit32u build_packet_header(Bit32u source, Bit32u dest, Bit8u protocol, Bit32u datalen);
+
+  eth_packet pending;
+  bx_bool is_pending;
+
+  //Bit8u Version; //=4 (4 bits)
+  //It better be!
+
+  //Bit8u IHL; //Header length in 32-bit bytes (4 bits)
+  //Used to strip layer
+
+  //Bit8u Type_of_Service; //not relevent, set to 0;
+  //Ignore on receive, set to 0 on send.
+
+  //Bit16u Total_Length;//length of the datagram in octets. use 576 or less;
+  //Use 576 or less on send.
+  //Use to get length on receive
+
+  //Bit16u Identification;//Identifier for assembling fragments
+  //Ignore, we'll drop fragments
+
+  //Bit8u Flags;//0,Don't fragment, More Fragments (vs last fragment)
+  //Set to 0 on send
+  //Drop if more fragments set.
+
+  //Bit16u Fragment Offset;//where in the datagram this fragment belongs
+  //Should be 0 for send and receive.
+
+  //Bit8u TTL;//Set to something sorta big.
+  //Shouldn't be 0 on receive
+  //Set to something big on send
+
+  //Bit8u Protocol;
+  //Defines Protocol.
+  //TCP=?, UDP=?
+
+  //Bit16u Header_Checksum;//16-bit one's complement of the one's complement
+                 //sum of all 16-bit words in header;
+  //Could check on receive, must set on send.
+
+  //Bit32u Source;//source address
+  //Bit32u Destination;//destination address
+};
+
+/*
+class eth_TCPmaker : eth_packetmaker {
+};
+
+class eth_UDPmaker : eth_packetmaker {
+};
+*/
+
+class eth_ETHmaker : public eth_packetmaker {
+public:
+  //handles all packets to a MAC addr.
+  void init(void);
+  virtual bx_bool getpacket(eth_packet& inpacket);
+  virtual bx_bool ishandler(const eth_packet& outpacket);
+  virtual bx_bool sendpacket(const eth_packet& outpacket);
+private:
+  eth_ARPmaker arper;
+};
+
+
+#endif // ETH_ARPBACK
+#endif // _ETH_PACKETMAKER_H_
+
diff --git a/tools/ioemu/iodev/eth_tap.cc b/tools/ioemu/iodev/eth_tap.cc
new file mode 100644 (file)
index 0000000..cb1bf1d
--- /dev/null
@@ -0,0 +1,370 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_tap.cc,v 1.16 2003/10/02 11:33:41 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth_tap.cc  - TAP interface by Bryce Denney
+//
+// Here's how to get this working.  On the host machine:
+//    $ su root
+//    # /sbin/insmod ethertap
+//    Using /lib/modules/2.2.14-5.0/net/ethertap.o
+//    # mknod /dev/tap0 c 36 16          # if not already there
+//    # /sbin/ifconfig tap0 10.0.0.1
+//    # /sbin/route add -host 10.0.0.2 gw 10.0.0.1
+//
+// Now you have a tap0 device which you can on the ifconfig output.  The
+// tap0 interface has the IP address of 10.0.0.1.  The bochs machine will have
+// the IP address 10.0.0.2.
+//
+// Compile a bochs version from March 8, 2002 or later with --enable-ne2000.
+// Add this ne2k line to your .bochsrc to activate the tap device.
+//   ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+// Don't change the mac or ethmod!
+//
+// Boot up DLX Linux in Bochs.  Log in as root and then type the following
+// commands to set up networking:
+//   # ifconfig eth0 10.0.0.2
+//   # route add -net 10.0.0.0
+//   # route add default gw 10.0.0.1
+// Now you should be able to ping from guest OS to your host machine, if
+// you give its IP number.  I'm still having trouble with pings from the
+// host machine to the guest, so something is still not right.  Symptoms: I
+// ping from the host to the guest's IP address 10.0.0.2.  With tcpdump I can
+// see the ping going to Bochs, and then the ping reply coming from Bochs.
+// But the ping program itself does not see the responses....well every
+// once in a while it does, like 1 in 60 pings.
+//
+// host$ ping 10.0.0.2
+// PING 10.0.0.2 (10.0.0.2) from 10.0.0.1 : 56(84) bytes of data.
+// 
+// Netstat output:
+// 20:29:59.018776 fe:fd:0:0:0:0 fe:fd:0:0:0:1 0800 98: 10.0.0.1 > 10.0.0.2: icmp: echo request
+//      4500 0054 2800 0000 4001 3ea7 0a00 0001
+//      0a00 0002 0800 09d3 a53e 0400 9765 893c
+//      3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
+//      1415 1617 1819
+// 20:29:59.023017 fe:fd:0:0:0:1 fe:fd:0:0:0:0 0800 98: 10.0.0.2 > 10.0.0.1: icmp: echo reply
+//      4500 0054 004a 0000 4001 665d 0a00 0002
+//      0a00 0001 0000 11d3 a53e 0400 9765 893c
+//      3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
+//      1415 1617 1819
+//
+// I suspect it may be related to the fact that ping 10.0.0.1 from the 
+// host also doesn't work.  Why wouldn't the host respond to its own IP 
+// address on the tap0 device?
+//
+// Theoretically, if you set up packet forwarding (with masquerading) on the
+// host, you should be able to get Bochs talking to anyone on the internet.
+// 
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#ifndef __APPLE__
+#include <sys/poll.h>
+#endif
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#if defined(__FreeBSD__) || defined(__APPLE__)  // Should be fixed for other *BSD
+#include <net/if.h>
+#else
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/if.h>
+#endif
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define TAP_VIRTUAL_HW_ADDR             0xDEADBEEF
+#define BX_ETH_TAP_LOGGING 1
+#define BX_PACKET_BUFSIZ 2048  // Enough for an ether frame
+
+//
+//  Define the class. This is private to this module
+//
+class bx_tap_pktmover_c : public eth_pktmover_c {
+public:
+  bx_tap_pktmover_c(const char *netif, const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+private:
+  int fd;
+  int rx_timer_index;
+  static void rx_timer_handler(void *);
+  void rx_timer ();
+  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_tap_locator_c : public eth_locator_c {
+public:
+  bx_tap_locator_c(void) : eth_locator_c("tap") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_tap_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_tap_match;
+
+
+//
+// Define the methods for the bx_tap_pktmover derived class
+//
+
+// the constructor
+bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+  int flags;
+  char filename[BX_PATHNAME_LEN];
+  if (strncmp (netif, "tap", 3) != 0) {
+    BX_PANIC (("eth_tap: interface name (%s) must be tap0..tap15", netif));
+  }
+  sprintf (filename, "/dev/%s", netif);
+
+#if defined(__linux__)
+  // check if the TAP devices is running, and turn on ARP.  This is based
+  // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
+  int sock = socket( AF_INET, SOCK_DGRAM, 0 );
+  if (sock < 0) {
+    BX_PANIC (("socket creation: %s", strerror(errno)));
+    return;
+  }
+  struct ifreq ifr;
+  memset( &ifr, 0, sizeof(ifr) );
+  strncpy( ifr.ifr_name, netif, sizeof(ifr.ifr_name) );
+  if( ioctl( sock, SIOCGIFFLAGS, &ifr ) < 0 ){
+    BX_PANIC (("SIOCGIFFLAGS on %s: %s", netif, strerror (errno)));
+    close(sock);
+    return;
+  }
+  if( !(ifr.ifr_flags & IFF_RUNNING ) ){
+    BX_PANIC (("%s device is not running", netif));
+    close(sock);
+    return;
+  }
+  if( (ifr.ifr_flags & IFF_NOARP ) ){
+    BX_INFO (("turn on ARP for %s device", netif));
+    ifr.ifr_flags &= ~IFF_NOARP;
+    if( ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0 ) {
+      BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno)));
+      close(sock);
+      return;
+    }
+  }
+  close(sock);
+#endif
+
+  fd = open (filename, O_RDWR);
+  if (fd < 0) {
+    BX_PANIC (("open failed on %s: %s", netif, strerror (errno)));
+    return;
+  }
+
+  /* set O_ASYNC flag so that we can poll with read() */
+  if ((flags = fcntl( fd, F_GETFL)) < 0) {
+    BX_PANIC (("getflags on tap device: %s", strerror (errno)));
+  }
+  flags |= O_NONBLOCK;
+  if (fcntl( fd, F_SETFL, flags ) < 0) {
+    BX_PANIC (("set tap device flags: %s", strerror (errno)));
+  }
+
+  BX_INFO (("eth_tap: opened %s device", netif));
+
+  /* Execute the configuration script */
+  char intname[IFNAMSIZ];
+  strcpy(intname,netif);
+  char *scriptname=bx_options.ne2k.Oscript->getptr();
+  if((scriptname != NULL)
+   &&(strcmp(scriptname, "") != 0)
+   &&(strcmp(scriptname, "none") != 0)) {
+    if (execute_script(scriptname, intname) < 0)
+      BX_ERROR (("execute script '%s' on %s failed", scriptname, intname));
+    }
+
+  // Start the rx poll 
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
+                               1, 1, "eth_tap"); // continuous, active
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+#if BX_ETH_TAP_LOGGING
+  // eventually Bryce wants txlog to dump in pcap format so that
+  // tcpdump -r FILE can read it and interpret packets.
+  txlog = fopen ("ne2k-tx.log", "wb");
+  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
+  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
+  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
+  fprintf (txlog_txt, "tap packetmover readable log file\n");
+  fprintf (txlog_txt, "net IF = %s\n", netif);
+  fprintf (txlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (txlog_txt, "\n--\n");
+  fflush (txlog_txt);
+
+  rxlog = fopen ("ne2k-rx.log", "wb");
+  if (!rxlog) BX_PANIC (("open ne2k-rx.log failed"));
+  rxlog_txt = fopen ("ne2k-rxdump.txt", "wb");
+  if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed"));
+  fprintf (rxlog_txt, "tap packetmover readable log file\n");
+  fprintf (rxlog_txt, "net IF = %s\n", netif);
+  fprintf (rxlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (rxlog_txt, "\n--\n");
+  fflush (rxlog_txt);
+
+#endif
+}
+
+void
+bx_tap_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+  Bit8u txbuf[BX_PACKET_BUFSIZ];
+  txbuf[0] = 0;
+  txbuf[1] = 0;
+#if defined(__FreeBSD__) || defined(__APPLE__)  // Should be fixed for other *BSD
+  memcpy (txbuf, buf, io_len);
+  unsigned int size = write (fd, txbuf, io_len);
+  if (size != io_len) {
+#else
+  memcpy (txbuf+2, buf, io_len);
+  unsigned int size = write (fd, txbuf, io_len+2);
+  if (size != io_len+2) {
+#endif
+    BX_PANIC (("write on tap device: %s", strerror (errno)));
+  } else {
+    BX_INFO (("wrote %d bytes + 2 byte pad on tap", io_len));
+  }
+#if BX_ETH_TAP_LOGGING
+  BX_DEBUG (("sendpkt length %u", io_len));
+  // dump raw bytes to a file, eventually dump in pcap format so that
+  // tcpdump -r FILE can interpret them for us.
+  int n = fwrite (buf, io_len, 1, txlog);
+  if (n != 1) BX_ERROR (("fwrite to txlog failed, io_len = %u", io_len));
+  // dump packet in hex into an ascii log file
+  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+  Bit8u *charbuf = (Bit8u *)buf;
+  for (n=0; n<(int)io_len; n++) {
+    if (((n % 16) == 0) && n>0)
+      fprintf (txlog_txt, "\n");
+    fprintf (txlog_txt, "%02x ", charbuf[n]);
+  }
+  fprintf (txlog_txt, "\n--\n");
+  // flush log so that we see the packets as they arrive w/o buffering
+  fflush (txlog);
+  fflush (txlog_txt);
+#endif
+}
+
+void bx_tap_pktmover_c::rx_timer_handler (void *this_ptr)
+{
+  bx_tap_pktmover_c *class_ptr = (bx_tap_pktmover_c *) this_ptr;
+  class_ptr->rx_timer();
+}
+
+void bx_tap_pktmover_c::rx_timer ()
+{
+  int nbytes;
+  Bit8u buf[BX_PACKET_BUFSIZ];
+  Bit8u *rxbuf;
+  if (fd<0) return;
+  nbytes = read (fd, buf, sizeof(buf));
+
+  // hack: discard first two bytes
+#if defined(__FreeBSD__) || defined(__APPLE__)  // Should be fixed for other *BSD
+  rxbuf = buf;
+#else
+  rxbuf = buf+2;
+  nbytes-=2;
+#endif
+  
+  // hack: TAP device likes to create an ethernet header which has
+  // the same source and destination address FE:FD:00:00:00:00.
+  // Change the dest address to FE:FD:00:00:00:01.
+#if defined(__linux__)
+  rxbuf[5] = 1;
+#endif
+
+  if (nbytes>0)
+    BX_INFO (("tap read returned %d bytes", nbytes));
+  if (nbytes<0) {
+    if (errno != EAGAIN)
+      BX_ERROR (("tap read error: %s", strerror(errno)));
+    return;
+  }
+#if BX_ETH_TAP_LOGGING
+  if (nbytes > 0) {
+    BX_DEBUG (("receive packet length %u", nbytes));
+    // dump raw bytes to a file, eventually dump in pcap format so that
+    // tcpdump -r FILE can interpret them for us.
+    int n = fwrite (rxbuf, nbytes, 1, rxlog);
+    if (n != 1) BX_ERROR (("fwrite to rxlog failed, nbytes = %d", nbytes));
+    // dump packet in hex into an ascii log file
+    fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
+    for (n=0; n<nbytes; n++) {
+      if (((n % 16) == 0) && n>0)
+       fprintf (rxlog_txt, "\n");
+      fprintf (rxlog_txt, "%02x ", rxbuf[n]);
+    }
+    fprintf (rxlog_txt, "\n--\n");
+    // flush log so that we see the packets as they arrive w/o buffering
+    fflush (rxlog);
+    fflush (rxlog_txt);
+  }
+#endif
+  BX_DEBUG(("eth_tap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
+  if (nbytes < 60) {
+    BX_INFO (("packet too short (%d), padding to 60", nbytes));
+    nbytes = 60;
+  }
+  (*rxh)(rxarg, rxbuf, nbytes);
+}
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/eth_tuntap.cc b/tools/ioemu/iodev/eth_tuntap.cc
new file mode 100644 (file)
index 0000000..f910fd5
--- /dev/null
@@ -0,0 +1,401 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: eth_tuntap.cc,v 1.9 2003/04/26 14:48:45 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// eth_tuntap.cc  - TUN/TAP interface by Renzo Davoli <renzo@cs.unibo.it>
+//
+// WARNING: These instructions were written for ethertap, not TUN/TAP.
+//
+// Here's how to get this working.  On the host machine:
+//    $ su root
+//    # /sbin/insmod ethertap
+//    Using /lib/modules/2.2.14-5.0/net/ethertap.o
+//    # mknod /dev/tap0 c 36 16          # if not already there
+//    # /sbin/ifconfig tap0 10.0.0.1
+//    # /sbin/route add -host 10.0.0.2 gw 10.0.0.1
+//
+// Now you have a tap0 device which you can on the ifconfig output.  The
+// tap0 interface has the IP address of 10.0.0.1.  The bochs machine will have
+// the IP address 10.0.0.2.
+//
+// Compile a bochs version from March 8, 2002 or later with --enable-ne2000.
+// Add this ne2k line to your .bochsrc to activate the tap device.
+//   ne2k: ioaddr=0x280, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+// Don't change the mac or ethmod!
+//
+// Boot up DLX Linux in Bochs.  Log in as root and then type the following
+// commands to set up networking:
+//   # ifconfig eth0 10.0.0.2
+//   # route add -net 10.0.0.0
+//   # route add default gw 10.0.0.1
+// Now you should be able to ping from guest OS to your host machine, if
+// you give its IP number.  I'm still having trouble with pings from the
+// host machine to the guest, so something is still not right.  Symptoms: I
+// ping from the host to the guest's IP address 10.0.0.2.  With tcpdump I can
+// see the ping going to Bochs, and then the ping reply coming from Bochs.
+// But the ping program itself does not see the responses....well every
+// once in a while it does, like 1 in 60 pings.
+//
+// host$ ping 10.0.0.2
+// PING 10.0.0.2 (10.0.0.2) from 10.0.0.1 : 56(84) bytes of data.
+// 
+// Netstat output:
+// 20:29:59.018776 fe:fd:0:0:0:0 fe:fd:0:0:0:1 0800 98: 10.0.0.1 > 10.0.0.2: icmp: echo request
+//      4500 0054 2800 0000 4001 3ea7 0a00 0001
+//      0a00 0002 0800 09d3 a53e 0400 9765 893c
+//      3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
+//      1415 1617 1819
+// 20:29:59.023017 fe:fd:0:0:0:1 fe:fd:0:0:0:0 0800 98: 10.0.0.2 > 10.0.0.1: icmp: echo reply
+//      4500 0054 004a 0000 4001 665d 0a00 0002
+//      0a00 0001 0000 11d3 a53e 0400 9765 893c
+//      3949 0000 0809 0a0b 0c0d 0e0f 1011 1213
+//      1415 1617 1819
+//
+// I suspect it may be related to the fact that ping 10.0.0.1 from the 
+// host also doesn't work.  Why wouldn't the host respond to its own IP 
+// address on the tap0 device?
+//
+// Theoretically, if you set up packet forwarding (with masquerading) on the
+// host, you should be able to get Bochs talking to anyone on the internet.
+// 
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT
+
+#define LOG_THIS bx_devices.pluginNE2kDevice->
+
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <asm/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <linux/netlink.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define TUNTAP_VIRTUAL_HW_ADDR             0xDEADBEEF
+#define BX_ETH_TUNTAP_LOGGING 0
+#define BX_PACKET_BUFSIZ 2048  // Enough for an ether frame
+
+int tun_alloc(char *dev);
+
+//
+//  Define the class. This is private to this module
+//
+class bx_tuntap_pktmover_c : public eth_pktmover_c {
+public:
+  bx_tuntap_pktmover_c(const char *netif, const char *macaddr,
+                    eth_rx_handler_t rxh,
+                    void *rxarg);
+  void sendpkt(void *buf, unsigned io_len);
+private:
+  int fd;
+  int rx_timer_index;
+  static void rx_timer_handler(void *);
+  void rx_timer ();
+  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
+};
+
+
+//
+//  Define the static class that registers the derived pktmover class,
+// and allocates one on request.
+//
+class bx_tuntap_locator_c : public eth_locator_c {
+public:
+  bx_tuntap_locator_c(void) : eth_locator_c("tuntap") {}
+protected:
+  eth_pktmover_c *allocate(const char *netif, const char *macaddr,
+                          eth_rx_handler_t rxh,
+                          void *rxarg) {
+    return (new bx_tuntap_pktmover_c(netif, macaddr, rxh, rxarg));
+  }
+} bx_tuntap_match;
+
+
+//
+// Define the methods for the bx_tuntap_pktmover derived class
+//
+
+// the constructor
+bx_tuntap_pktmover_c::bx_tuntap_pktmover_c(const char *netif, 
+                                      const char *macaddr,
+                                      eth_rx_handler_t rxh,
+                                      void *rxarg)
+{
+  int flags;
+  if (strncmp (netif, "tun", 3) != 0) {
+    BX_PANIC (("eth_tuntap: interface name (%s) must be tun", netif));
+  }
+#ifdef NEVERDEF
+  char filename[BX_PATHNAME_LEN];
+  sprintf (filename, "/dev/net/%s", netif);
+
+  // check if the TUN/TAP devices is running, and turn on ARP.  This is based
+  // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/
+  int sock = socket( AF_INET, SOCK_DGRAM, 0 );
+  if (sock < 0) {
+    BX_PANIC (("socket creation: %s", strerror(errno)));
+    return;
+  }
+  struct ifreq ifr;
+  memset( &ifr, 0, sizeof(ifr) );
+  strncpy( ifr.ifr_name, netif, sizeof(ifr.ifr_name) );
+  if( ioctl( sock, SIOCGIFFLAGS, &ifr ) < 0 ){
+    BX_PANIC (("SIOCGIFFLAGS on %s: %s", netif, strerror (errno)));
+    close(sock);
+    return;
+  }
+  if( !(ifr.ifr_flags & IFF_RUNNING ) ){
+    BX_PANIC (("%s device is not running", netif));
+    close(sock);
+    return;
+  }
+  if( (ifr.ifr_flags & IFF_NOARP ) ){
+    BX_INFO (("turn on ARP for %s device", netif));
+    ifr.ifr_flags &= ~IFF_NOARP;
+    if( ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0 ) {
+      BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno)));
+      close(sock);
+      return;
+    }
+  }
+  close(sock);
+
+  fd = open (filename, O_RDWR);
+#endif 
+  char intname[IFNAMSIZ];
+  strcpy(intname,netif);
+  fd=tun_alloc(intname);
+  if (fd < 0) {
+    BX_PANIC (("open failed on %s: %s", netif, strerror (errno)));
+    return;
+  }
+
+  /* set O_ASYNC flag so that we can poll with read() */
+  if ((flags = fcntl( fd, F_GETFL)) < 0) {
+    BX_PANIC (("getflags on tun device: %s", strerror (errno)));
+  }
+  flags |= O_NONBLOCK;
+  if (fcntl( fd, F_SETFL, flags ) < 0) {
+    BX_PANIC (("set tun device flags: %s", strerror (errno)));
+  }
+
+  BX_INFO (("eth_tuntap: opened %s device", netif));
+
+  /* Execute the configuration script */
+  char *scriptname=bx_options.ne2k.Oscript->getptr();
+  if((scriptname != NULL)
+   &&(strcmp(scriptname, "") != 0)
+   &&(strcmp(scriptname, "none") != 0)) {
+    if (execute_script(scriptname, intname) < 0)
+      BX_ERROR (("execute script '%s' on %s failed", scriptname, intname));
+    }
+
+  // Start the rx poll 
+  this->rx_timer_index = 
+    bx_pc_system.register_timer(this, this->rx_timer_handler, 1000,
+                               1, 1, "eth_tuntap"); // continuous, active
+  this->rxh   = rxh;
+  this->rxarg = rxarg;
+#if BX_ETH_TUNTAP_LOGGING
+  // eventually Bryce wants txlog to dump in pcap format so that
+  // tcpdump -r FILE can read it and interpret packets.
+  txlog = fopen ("ne2k-tx.log", "wb");
+  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
+  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
+  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
+  fprintf (txlog_txt, "tuntap packetmover readable log file\n");
+  fprintf (txlog_txt, "net IF = %s\n", netif);
+  fprintf (txlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (txlog_txt, "\n--\n");
+  fflush (txlog_txt);
+
+  rxlog = fopen ("ne2k-rx.log", "wb");
+  if (!rxlog) BX_PANIC (("open ne2k-rx.log failed"));
+  rxlog_txt = fopen ("ne2k-rxdump.txt", "wb");
+  if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed"));
+  fprintf (rxlog_txt, "tuntap packetmover readable log file\n");
+  fprintf (rxlog_txt, "net IF = %s\n", netif);
+  fprintf (rxlog_txt, "MAC address = ");
+  for (int i=0; i<6; i++) 
+    fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
+  fprintf (rxlog_txt, "\n--\n");
+  fflush (rxlog_txt);
+
+#endif
+}
+
+void
+bx_tuntap_pktmover_c::sendpkt(void *buf, unsigned io_len)
+{
+#ifdef NEVERDEF
+  Bit8u txbuf[BX_PACKET_BUFSIZ];
+  txbuf[0] = 0;
+  txbuf[1] = 0;
+  memcpy (txbuf+2, buf, io_len);
+  unsigned int size = write (fd, txbuf, io_len+2);
+  if (size != io_len+2) {
+    BX_PANIC (("write on tuntap device: %s", strerror (errno)));
+  } else {
+    BX_INFO (("wrote %d bytes + 2 byte pad on tuntap", io_len));
+  }
+#endif
+  unsigned int size = write (fd, buf, io_len);
+  if (size != io_len) {
+    BX_PANIC (("write on tuntap device: %s", strerror (errno)));
+  } else {
+    BX_INFO (("wrote %d bytes on tuntap", io_len));
+  }
+#if BX_ETH_TUNTAP_LOGGING
+  BX_DEBUG (("sendpkt length %u", io_len));
+  // dump raw bytes to a file, eventually dump in pcap format so that
+  // tcpdump -r FILE can interpret them for us.
+  int n = fwrite (buf, io_len, 1, txlog);
+  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
+  // dump packet in hex into an ascii log file
+  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
+  Bit8u *charbuf = (Bit8u *)buf;
+  for (n=0; n<io_len; n++) {
+    if (((n % 16) == 0) && n>0)
+      fprintf (txlog_txt, "\n");
+    fprintf (txlog_txt, "%02x ", charbuf[n]);
+  }
+  fprintf (txlog_txt, "\n--\n");
+  // flush log so that we see the packets as they arrive w/o buffering
+  fflush (txlog);
+  fflush (txlog_txt);
+#endif
+}
+
+void bx_tuntap_pktmover_c::rx_timer_handler (void *this_ptr)
+{
+  bx_tuntap_pktmover_c *class_ptr = (bx_tuntap_pktmover_c *) this_ptr;
+  class_ptr->rx_timer();
+}
+
+void bx_tuntap_pktmover_c::rx_timer ()
+{
+  int nbytes;
+  Bit8u buf[BX_PACKET_BUFSIZ];
+  Bit8u *rxbuf;
+  if (fd<0) return;
+  nbytes = read (fd, buf, sizeof(buf));
+
+#ifdef NEVERDEF
+  // hack: discard first two bytes
+  rxbuf = buf+2;
+  nbytes-=2;
+#else
+  rxbuf=buf;
+#endif
+
+  // hack: TUN/TAP device likes to create an ethernet header which has
+  // the same source and destination address FE:FD:00:00:00:00.
+  // Change the dest address to FE:FD:00:00:00:01.
+  rxbuf[5] = 1;
+
+  if (nbytes>0)
+    BX_INFO (("tuntap read returned %d bytes", nbytes));
+  if (nbytes<0) {
+    if (errno != EAGAIN)
+      BX_ERROR (("tuntap read error: %s", strerror(errno)));
+    return;
+  }
+#if BX_ETH_TUNTAP_LOGGING
+  if (nbytes > 0) {
+    BX_DEBUG (("receive packet length %u", nbytes));
+    // dump raw bytes to a file, eventually dump in pcap format so that
+    // tcpdump -r FILE can interpret them for us.
+    int n = fwrite (rxbuf, nbytes, 1, rxlog);
+    if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
+    // dump packet in hex into an ascii log file
+    fprintf (rxlog_txt, "NE2K received a packet, length %u\n", nbytes);
+    for (n=0; n<nbytes; n++) {
+      if (((n % 16) == 0) && n>0)
+       fprintf (rxlog_txt, "\n");
+      fprintf (rxlog_txt, "%02x ", rxbuf[n]);
+    }
+    fprintf (rxlog_txt, "\n--\n");
+    // flush log so that we see the packets as they arrive w/o buffering
+    fflush (rxlog);
+    fflush (rxlog_txt);
+  }
+#endif
+  BX_DEBUG(("eth_tuntap: got packet: %d bytes, dst=%x:%x:%x:%x:%x:%x, src=%x:%x:%x:%x:%x:%x\n", nbytes, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4], rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9], rxbuf[10], rxbuf[11]));
+  if (nbytes < 60) {
+    BX_INFO (("packet too short (%d), padding to 60", nbytes));
+    nbytes = 60;
+  }
+  (*rxh)(rxarg, rxbuf, nbytes);
+}
+
+
+  int tun_alloc(char *dev)
+  {
+      struct ifreq ifr;
+      int fd, err;
+
+      if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
+         return -1;
+
+      memset(&ifr, 0, sizeof(ifr));
+
+      /* Flags: IFF_TUN   - TUN device (no Ethernet headers) 
+       *        IFF_TAP   - TAP device  
+       *
+       *        IFF_NO_PI - Do not provide packet information  
+       */ 
+      ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 
+      if( *dev )
+         strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+
+      if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
+         close(fd);
+         return err;
+      }
+
+      //strcpy(dev, ifr.ifr_name);
+      ioctl( fd, TUNSETNOCSUM, 1 );
+
+      return fd;
+  }              
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/extfpuirq.cc b/tools/ioemu/iodev/extfpuirq.cc
new file mode 100644 (file)
index 0000000..5d1ed98
--- /dev/null
@@ -0,0 +1,107 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extfpuirq.cc,v 1.5 2003/07/31 12:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// External circuit for MSDOS compatible FPU exceptions
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theExternalFpuIrq->
+
+bx_extfpuirq_c *theExternalFpuIrq = NULL;
+
+  int
+libextfpuirq_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theExternalFpuIrq = new bx_extfpuirq_c ();
+  bx_devices.pluginExtFpuIrq = theExternalFpuIrq;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theExternalFpuIrq, BX_PLUGIN_EXTFPUIRQ);
+  return(0); // Success
+}
+
+  void
+libextfpuirq_LTX_plugin_fini(void)
+{
+}
+
+bx_extfpuirq_c::bx_extfpuirq_c(void)
+{
+  put("EFIRQ");
+  settype(EXTFPUIRQLOG);
+}
+
+bx_extfpuirq_c::~bx_extfpuirq_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_extfpuirq_c::init(void)
+{
+  // called once when bochs initializes
+  DEV_register_iowrite_handler(this, write_handler, 0x00F0, "External FPU IRQ", 1);
+  DEV_register_irq(13, "External FPU IRQ");
+}
+
+  void
+bx_extfpuirq_c::reset(unsigned type)
+{
+  // We should handle IGNNE here
+  DEV_pic_lower_irq(13);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_extfpuirq_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_EFI_SMF
+  bx_extfpuirq_c *class_ptr = (bx_extfpuirq_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_extfpuirq_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_EFI_SMF
+
+  // We should handle IGNNE here
+  DEV_pic_lower_irq(13);
+}
+
diff --git a/tools/ioemu/iodev/extfpuirq.h b/tools/ioemu/iodev/extfpuirq.h
new file mode 100644 (file)
index 0000000..c32e71a
--- /dev/null
@@ -0,0 +1,51 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: extfpuirq.h,v 1.2 2003/01/07 08:17:15 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#if BX_USE_EFI_SMF
+#  define BX_EXTFPUIRQ_SMF  static
+#  define BX_EXTFPUIRQ_THIS theExternalFpuIrq->
+#else
+#  define BX_EXTFPUIRQ_SMF
+#  define BX_EXTFPUIRQ_THIS this->
+#endif
+
+
+class bx_extfpuirq_c : public bx_devmodel_c {
+
+public:
+  bx_extfpuirq_c(void);
+  ~bx_extfpuirq_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_EFI_SMF
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+  };
diff --git a/tools/ioemu/iodev/floppy.cc b/tools/ioemu/iodev/floppy.cc
new file mode 100644 (file)
index 0000000..e4090d5
--- /dev/null
@@ -0,0 +1,1633 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppy.cc,v 1.69 2003/12/18 20:04:49 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+//
+// Floppy Disk Controller Docs:
+// Intel 82077A Data sheet
+//   ftp://void-core.2y.net/pub/docs/fdc/82077AA_FloppyControllerDatasheet.pdf
+// Intel 82078 Data sheet
+//   ftp://download.intel.com/design/periphrl/datashts/29047403.PDF
+// Other FDC references
+//   http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html
+// And a port list:
+//   http://mudlist.eorbit.net/~adam/pickey/ports.html
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+
+extern "C" {
+#include <errno.h>
+}
+
+#ifdef __linux__
+extern "C" {
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+}
+#endif
+#include "bochs.h"
+// windows.h included by bochs.h
+#ifdef WIN32
+extern "C" {
+#include <winioctl.h>
+}
+#endif
+#define LOG_THIS theFloppyController->
+
+bx_floppy_ctrl_c *theFloppyController;
+
+/* for main status register */
+#define FD_MS_MRQ  0x80
+#define FD_MS_DIO  0x40
+#define FD_MS_NDMA 0x20
+#define FD_MS_BUSY 0x10
+#define FD_MS_ACTD 0x08
+#define FD_MS_ACTC 0x04
+#define FD_MS_ACTB 0x02
+#define FD_MS_ACTA 0x01
+
+#define FROM_FLOPPY 10
+#define TO_FLOPPY   11
+
+#define FLOPPY_DMA_CHAN 2
+
+typedef struct {
+  unsigned id;
+  Bit8u trk;
+  Bit8u hd;
+  Bit8u spt;
+  unsigned sectors;
+} floppy_type_t;
+
+static floppy_type_t floppy_type[8] = {
+  {BX_FLOPPY_160K, 40, 1, 8, 320},
+  {BX_FLOPPY_180K, 40, 1, 9, 360},
+  {BX_FLOPPY_320K, 40, 2, 8, 640},
+  {BX_FLOPPY_360K, 40, 2, 9, 720},
+  {BX_FLOPPY_720K, 80, 2, 9, 1440},
+  {BX_FLOPPY_1_2,  80, 2, 15, 2400},
+  {BX_FLOPPY_1_44, 80, 2, 18, 2880},
+  {BX_FLOPPY_2_88, 80, 2, 36, 5760}
+};
+
+
+  int
+libfloppy_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theFloppyController = new bx_floppy_ctrl_c ();
+  bx_devices.pluginFloppyDevice = theFloppyController;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theFloppyController, BX_PLUGIN_FLOPPY);
+  return(0); // Success
+}
+
+  void
+libfloppy_LTX_plugin_fini(void)
+{
+}
+
+
+bx_floppy_ctrl_c::bx_floppy_ctrl_c(void)
+{
+  put("FDD");
+  settype(FDLOG);
+  s.floppy_timer_index = BX_NULL_TIMER_HANDLE;
+}
+
+bx_floppy_ctrl_c::~bx_floppy_ctrl_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_floppy_ctrl_c::init(void)
+{
+  Bit8u i;
+
+  BX_DEBUG(("Init $Id: floppy.cc,v 1.69 2003/12/18 20:04:49 vruppert Exp $"));
+  DEV_dma_register_8bit_channel(2, dma_read, dma_write, "Floppy Drive");
+  DEV_register_irq(6, "Floppy Drive");
+  for (unsigned addr=0x03F2; addr<=0x03F7; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "Floppy Drive", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "Floppy Drive", 1);
+    }
+
+
+  DEV_cmos_set_reg(0x10, 0x00); /* start out with: no drive 0, no drive 1 */
+
+  BX_FD_THIS s.num_supported_floppies = 0;
+
+  for (i=0; i<4; i++) {
+    BX_FD_THIS s.device_type[i] = BX_FLOPPY_NONE;
+    BX_FD_THIS s.media[i].type = BX_FLOPPY_NONE;
+    }
+
+  //
+  // Floppy A setup
+  //
+  BX_FD_THIS s.media[0].sectors_per_track = 0;
+  BX_FD_THIS s.media[0].tracks            = 0;
+  BX_FD_THIS s.media[0].heads             = 0;
+  BX_FD_THIS s.media[0].sectors           = 0;
+  BX_FD_THIS s.media[0].fd = -1;
+  BX_FD_THIS s.media_present[0] = 0;
+  BX_FD_THIS s.device_type[0] = bx_options.floppya.Odevtype->get ();
+
+  switch (BX_FD_THIS s.device_type[0]) {
+    case BX_FLOPPY_NONE:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x00);
+      break;
+    case BX_FLOPPY_360K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x10);
+      break;
+    case BX_FLOPPY_1_2:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x20);
+      break;
+    case BX_FLOPPY_720K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x30);
+      break;
+    case BX_FLOPPY_1_44:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x40);
+      break;
+    case BX_FLOPPY_2_88:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x50);
+      break;
+
+    // use CMOS reserved types
+    case BX_FLOPPY_160K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x60);
+      BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 6"));
+      break;
+    case BX_FLOPPY_180K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x70);
+      BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 7"));
+      break;
+    case BX_FLOPPY_320K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0x0f) | 0x80);
+      BX_INFO(("WARNING: 1st floppy uses of reserved CMOS floppy drive type 8"));
+      break;
+
+    default:
+      BX_PANIC(("unknown floppya type"));
+    }
+  if (BX_FD_THIS s.device_type[0] != BX_FLOPPY_NONE)
+    BX_FD_THIS s.num_supported_floppies++;
+
+  if (bx_options.floppya.Otype->get () != BX_FLOPPY_NONE) {
+    if ( bx_options.floppya.Ostatus->get () == BX_INSERTED) {
+      if (evaluate_media(bx_options.floppya.Otype->get (), bx_options.floppya.Opath->getptr (),
+                   & BX_FD_THIS s.media[0]))
+        BX_FD_THIS s.media_present[0] = 1;
+      else
+        bx_options.floppya.Ostatus->set(BX_EJECTED);
+#define MED (BX_FD_THIS s.media[0])
+        BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
+        MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+      }
+    }
+
+
+  //
+  // Floppy B setup
+  //
+  BX_FD_THIS s.media[1].sectors_per_track = 0;
+  BX_FD_THIS s.media[1].tracks            = 0;
+  BX_FD_THIS s.media[1].heads             = 0;
+  BX_FD_THIS s.media[1].sectors           = 0;
+  BX_FD_THIS s.media[1].fd = -1;
+  BX_FD_THIS s.media_present[1] = 0;
+  BX_FD_THIS s.device_type[1] = bx_options.floppyb.Odevtype->get ();
+
+  switch (BX_FD_THIS s.device_type[1]) {
+    case BX_FLOPPY_NONE:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x00);
+      break;
+    case BX_FLOPPY_360K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x01);
+      break;
+    case BX_FLOPPY_1_2:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x02);
+      break;
+    case BX_FLOPPY_720K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x03);
+      break;
+    case BX_FLOPPY_1_44:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x04);
+      break;
+    case BX_FLOPPY_2_88:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x05);
+      break;
+
+    // use CMOS reserved types
+    case BX_FLOPPY_160K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x06);
+      BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 6"));
+      break;
+    case BX_FLOPPY_180K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x07);
+      BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 7"));
+      break;
+    case BX_FLOPPY_320K:
+      DEV_cmos_set_reg(0x10, (DEV_cmos_get_reg(0x10) & 0xf0) | 0x08);
+      BX_INFO(("WARNING: 2nd floppy uses of reserved CMOS floppy drive type 8"));
+      break;
+
+    default:
+      BX_PANIC(("unknown floppyb type"));
+    }
+  if (BX_FD_THIS s.device_type[1] != BX_FLOPPY_NONE)
+    BX_FD_THIS s.num_supported_floppies++;
+
+  if (bx_options.floppyb.Otype->get () != BX_FLOPPY_NONE) {
+    if ( bx_options.floppyb.Ostatus->get () == BX_INSERTED) {
+      if (evaluate_media(bx_options.floppyb.Otype->get (), bx_options.floppyb.Opath->getptr (),
+                   & BX_FD_THIS s.media[1]))
+        BX_FD_THIS s.media_present[1] = 1;
+      else
+        bx_options.floppyb.Ostatus->set(BX_EJECTED);
+#define MED (BX_FD_THIS s.media[1])
+        BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
+        MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+      }
+    }
+
+
+
+  /* CMOS Equipment Byte register */
+  if (BX_FD_THIS s.num_supported_floppies > 0) {
+    DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e) |
+                          ((BX_FD_THIS s.num_supported_floppies-1) << 6) | 1);
+  }
+  else
+    DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0x3e));
+
+
+  if (BX_FD_THIS s.floppy_timer_index == BX_NULL_TIMER_HANDLE) {
+    BX_FD_THIS s.floppy_timer_index =
+      bx_pc_system.register_timer( this, timer_handler,
+      bx_options.Ofloppy_command_delay->get (), 0,0, "floppy");
+  }
+
+  BX_DEBUG(("bx_options.Ofloppy_command_delay = %u",
+    (unsigned) bx_options.Ofloppy_command_delay->get ()));
+}
+
+
+
+  void
+bx_floppy_ctrl_c::reset(unsigned type)
+{
+  Bit32u i;
+
+  BX_FD_THIS s.pending_irq = 0;
+  BX_FD_THIS s.reset_sensei = 0; /* no reset result present */
+
+  BX_FD_THIS s.main_status_reg = 0;
+  BX_FD_THIS s.status_reg0 = 0;
+  BX_FD_THIS s.status_reg1 = 0;
+  BX_FD_THIS s.status_reg2 = 0;
+  BX_FD_THIS s.status_reg3 = 0;
+
+  // software reset (via DOR port 0x3f2 bit 2) does not change DOR
+  if (type == BX_RESET_HARDWARE) {
+    BX_FD_THIS s.DOR = 0x0c;
+    // motor off, drive 3..0
+    // DMA/INT enabled
+    // normal operation
+    // drive select 0
+
+    // DIR and CCR affected only by hard reset
+    for (i=0; i<4; i++) {
+      BX_FD_THIS s.DIR[i] |= 0x80; // disk changed
+      }
+    BX_FD_THIS s.data_rate = 0; /* 500 Kbps */
+    }
+
+  for (i=0; i<4; i++) {
+    BX_FD_THIS s.cylinder[i] = 0;
+    BX_FD_THIS s.head[i] = 0;
+    BX_FD_THIS s.sector[i] = 0;
+    }
+
+  DEV_pic_lower_irq(6);
+  DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+  enter_idle_phase();
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_floppy_ctrl_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+  bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  /* reads from the floppy io ports */
+  Bit32u
+bx_floppy_ctrl_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_FD_SMF
+  Bit8u status, value;
+
+  if (bx_dbg.floppy)
+    BX_INFO(("read access to port %04x", (unsigned) address));
+
+  switch (address) {
+#if BX_DMA_FLOPPY_IO
+    case 0x3F2: // diskette controller digital output register
+      value = BX_FD_THIS s.DOR;
+      return(value);
+      break;
+
+    case 0x3F4: /* diskette controller main status register */
+      status = BX_FD_THIS s.main_status_reg;
+      return(status);
+      break;
+
+    case 0x3F5: /* diskette controller data */
+      if (BX_FD_THIS s.result_size == 0) {
+        BX_ERROR(("port 0x3f5: no results to read"));
+        BX_FD_THIS s.main_status_reg = 0;
+        return BX_FD_THIS s.result[0];
+        }
+
+      value = BX_FD_THIS s.result[BX_FD_THIS s.result_index++];
+      BX_FD_THIS s.main_status_reg &= 0xF0;
+      if (BX_FD_THIS s.result_index >= BX_FD_THIS s.result_size) {
+        if (!BX_FD_THIS s.reset_sensei) BX_FD_THIS s.pending_irq = 0;
+        DEV_pic_lower_irq(6);
+        enter_idle_phase();
+        }
+      return(value);
+      break;
+#endif  // #if BX_DMA_FLOPPY_IO
+
+    case 0x3F3: // Tape Drive Register
+      // see http://www.smsc.com/main/datasheets/37c93x.pdf page 18 for more details
+
+      switch( BX_FD_THIS s.DOR & 0x03 )
+      {
+        case 0x00:
+          if( (BX_FD_THIS s.DOR & 0x10) == 0) break;
+          return(2);
+        case 0x01:
+          if( (BX_FD_THIS s.DOR & 0x20) == 0) break;
+          return(1);
+      }
+      return(3);
+      
+    case 0x3F6: // Reserved for future floppy controllers
+                // This address shared with the hard drive controller
+      value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
+      return( value );
+      break;
+
+    case 0x3F7: // diskette controller digital input register
+      // This address shared with the hard drive controller:
+      //   Bit  7   : floppy
+      //   Bits 6..0: hard drive
+      value = DEV_hd_read_handler(bx_devices.pluginHardDrive, address, io_len);
+      value &= 0x7f;
+      // add in diskette change line
+      value |= (BX_FD_THIS s.DIR[BX_FD_THIS s.DOR & 0x03] & 0x80);
+      return( value );
+      break;
+    default:
+      BX_ERROR(("io_read: unsupported address 0x%04x", (unsigned) address));
+      return(0);
+      break;
+    }
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_floppy_ctrl_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_FD_SMF
+  bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  /* writes to the floppy io ports */
+  void
+bx_floppy_ctrl_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_FD_SMF
+  Bit8u dma_and_interrupt_enable;
+  Bit8u normal_operation, prev_normal_operation;
+  Bit8u drive_select;
+  Bit8u motor_on_drive0, motor_on_drive1;
+
+  if (bx_dbg.floppy)
+    BX_INFO(("write access to port %04x, value=%02x",
+      (unsigned) address, (unsigned) value));
+
+  switch (address) {
+#if BX_DMA_FLOPPY_IO
+    case 0x3F2: /* diskette controller digital output register */
+      motor_on_drive1 = value & 0x20;
+      motor_on_drive0 = value & 0x10;
+      dma_and_interrupt_enable = value & 0x08;
+      if (!dma_and_interrupt_enable)
+        BX_DEBUG(("DMA and interrupt capabilities disabled"));
+      normal_operation = value & 0x04;
+      drive_select = value & 0x03;
+
+      prev_normal_operation = BX_FD_THIS s.DOR & 0x04;
+      BX_FD_THIS s.DOR = value;
+
+      if (prev_normal_operation==0 && normal_operation) {
+        // transition from RESET to NORMAL
+        bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+             bx_options.Ofloppy_command_delay->get (), 0 );
+        }
+      else if (prev_normal_operation && normal_operation==0) {
+        // transition from NORMAL to RESET
+        BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+        BX_FD_THIS s.pending_command = 0xfe; // RESET pending
+
+        }
+        BX_DEBUG(("io_write: digital output register"));
+        BX_DEBUG(("  motor on, drive1 = %d", motor_on_drive1 > 0));
+        BX_DEBUG(("  motor on, drive0 = %d", motor_on_drive0 > 0));
+        BX_DEBUG(("  dma_and_interrupt_enable=%02x",
+          (unsigned) dma_and_interrupt_enable));
+        BX_DEBUG(("  normal_operation=%02x",
+          (unsigned) normal_operation));
+        BX_DEBUG(("  drive_select=%02x",
+          (unsigned) drive_select));
+      if (BX_FD_THIS s.device_type[drive_select] == BX_FLOPPY_NONE) {
+        BX_DEBUG(("WARNING: not existing drive selected"));
+        }
+      break;
+
+    case 0x3f4: /* diskette controller data rate select register */
+      BX_ERROR(("io_write: data rate select register unsupported"));
+      break;
+
+    case 0x3F5: /* diskette controller data */
+      BX_DEBUG(("command = %02x", (unsigned) value));
+      if (BX_FD_THIS s.command_complete) {
+        if (BX_FD_THIS s.pending_command!=0)
+          BX_PANIC(("io: 3f5: receiving new comm, old one (%02x) pending",
+            (unsigned) BX_FD_THIS s.pending_command));
+        BX_FD_THIS s.command[0] = value;
+        BX_FD_THIS s.command_complete = 0;
+        BX_FD_THIS s.command_index = 1;
+        /* read/write command in progress */
+        BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_BUSY;
+        switch (value) {
+          case 0x03: /* specify */
+            BX_FD_THIS s.command_size = 3;
+            break;
+          case 0x04: // get status
+            BX_FD_THIS s.command_size = 2;
+            break;
+          case 0x07: /* recalibrate */
+            BX_FD_THIS s.command_size = 2;
+            break;
+          case 0x08: /* sense interrupt status */
+            BX_FD_THIS s.command_size = 1;
+            break;
+          case 0x0f: /* seek */
+            BX_FD_THIS s.command_size = 3;
+            break;
+          case 0x4a: /* read ID */
+            BX_FD_THIS s.command_size = 2;
+            break;
+          case 0x4d: /* format track */
+            BX_FD_THIS s.command_size = 6;
+            break;
+          case 0x45:
+          case 0xc5: /* write normal data */
+            BX_FD_THIS s.command_size = 9;
+            break;
+          case 0x46:
+          case 0x66:
+          case 0xc6:
+          case 0xe6: /* read normal data */
+            BX_FD_THIS s.command_size = 9;
+            break;
+
+          case 0x13: // Configure command (Enhanced)
+            BX_FD_THIS s.command_size = 4;
+            break;
+
+          case 0x0e: // dump registers (Enhanced drives)
+          case 0x10: // Version command, standard controller returns 80h
+          case 0x18: // National Semiconductor version command; return 80h
+            // These commands are not implemented on the standard
+            // controller and return an error.  They are available on
+            // the enhanced controller.
+            BX_DEBUG(("io_write: 0x3f5: unsupported floppy command 0x%02x",
+              (unsigned) value));
+            BX_FD_THIS s.command_size = 0;   // make sure we don't try to process this command
+            BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+            enter_result_phase();
+            break;
+
+          default:
+            BX_ERROR(("io_write: 0x3f5: invalid floppy command 0x%02x",
+              (unsigned) value));
+            BX_FD_THIS s.command_size = 0;   // make sure we don't try to process this command
+            BX_FD_THIS s.status_reg0 = 0x80; // status: invalid command
+            enter_result_phase();
+            break;
+          }
+        }
+      else {
+        BX_FD_THIS s.command[BX_FD_THIS s.command_index++] =
+          value;
+        }
+      if (BX_FD_THIS s.command_index ==
+        BX_FD_THIS s.command_size) {
+        /* read/write command not in progress any more */
+        floppy_command();
+        BX_FD_THIS s.command_complete = 1;
+        }
+      BX_DEBUG(("io_write: diskette controller data"));
+      return;
+      break;
+#endif  // #if BX_DMA_FLOPPY_IO
+
+    case 0x3F6: /* diskette controller (reserved) */
+      BX_DEBUG(("io_write: reserved register 0x3f6 unsupported"));
+      // this address shared with the hard drive controller
+      DEV_hd_write_handler(bx_devices.pluginHardDrive, address, value, io_len);
+      break;
+
+#if BX_DMA_FLOPPY_IO
+    case 0x3F7: /* diskette controller configuration control register */
+      BX_DEBUG(("io_write: config control register"));
+      BX_FD_THIS s.data_rate = value & 0x03;
+      switch (BX_FD_THIS s.data_rate) {
+        case 0: BX_DEBUG(("  500 Kbps")); break;
+        case 1: BX_DEBUG(("  300 Kbps")); break;
+        case 2: BX_DEBUG(("  250 Kbps")); break;
+        case 3: BX_DEBUG(("  1 Mbps")); break;
+      }
+      return;
+      break;
+
+   default:
+      BX_ERROR(("io_write ignored: 0x%04x = 0x%02x", (unsigned) address, (unsigned) value));
+      break;
+#endif  // #if BX_DMA_FLOPPY_IO
+    }
+}
+
+
+
+  void
+bx_floppy_ctrl_c::floppy_command(void)
+{
+#if BX_PROVIDE_CPU_MEMORY==0
+  BX_PANIC(("floppy_command(): uses DMA: not supported for"
+           " external environment"));
+#else
+  unsigned i;
+  Bit8u step_rate_time;
+  Bit8u head_unload_time;
+  Bit8u head_load_time;
+  Bit8u motor_on;
+  Bit8u head, drive, cylinder, sector, eot;
+  Bit8u sector_size, data_length;
+  Bit32u logical_sector;
+
+
+  BX_DEBUG(("FLOPPY COMMAND: "));
+  for (i=0; i<BX_FD_THIS s.command_size; i++)
+    BX_DEBUG(("[%02x] ", (unsigned) BX_FD_THIS s.command[i]));
+
+#if 0
+  /* execute phase of command is in progress (non DMA mode) */
+  BX_FD_THIS s.main_status_reg |= 20;
+#endif
+
+  BX_FD_THIS s.pending_command = BX_FD_THIS s.command[0];
+  switch (BX_FD_THIS s.pending_command) {
+    case 0x03: // specify
+      // execution: specified parameters are loaded
+      // result: no result bytes, no interrupt
+      step_rate_time = BX_FD_THIS s.command[1] >> 4;
+      head_unload_time = BX_FD_THIS s.command[1] & 0x0f;
+      head_load_time = BX_FD_THIS s.command[2] >> 1;
+      if (BX_FD_THIS s.command[2] & 0x01)
+        BX_ERROR(("non DMA mode selected"));
+      enter_idle_phase();
+      return;
+      break;
+
+    case 0x04: // get status
+      drive = (BX_FD_THIS s.command[1] & 0x03);
+      BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+      BX_FD_THIS s.status_reg3 = 0x28 | (BX_FD_THIS s.head[drive]<<2) | drive
+        | (BX_FD_THIS s.media[drive].write_protected ? 0x40 : 0x00);
+      if (BX_FD_THIS s.cylinder[drive] == 0) BX_FD_THIS s.status_reg3 |= 0x10;
+      enter_result_phase();
+      return;
+      break;
+
+    case 0x07: // recalibrate
+      drive = (BX_FD_THIS s.command[1] & 0x03);
+      BX_FD_THIS s.DOR &= 0xfc;
+      BX_FD_THIS s.DOR |= drive;
+      BX_DEBUG(("floppy_command(): recalibrate drive %u",
+        (unsigned) drive));
+      motor_on = ( (BX_FD_THIS s.DOR>>(drive+4))
+                     & 0x01 );
+      if (motor_on == 0) {
+        BX_INFO(("floppy_command(): recal drive with motor off"));
+        }
+      if (drive==0)
+        BX_FD_THIS s.DOR |= 0x10; // turn on MOTA
+      else
+        BX_FD_THIS s.DOR |= 0x20; // turn on MOTB
+      bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+        bx_options.Ofloppy_command_delay->get (), 0 );
+      /* command head to track 0
+       * controller set to non-busy
+       * error condition noted in Status reg 0's equipment check bit
+       * seek end bit set to 1 in Status reg 0 regardless of outcome
+       * The last two are taken care of in timer().
+       */
+      BX_FD_THIS s.cylinder[drive] = 0;
+      BX_FD_THIS s.main_status_reg = (1 << drive);
+      return;
+      break;
+
+    case 0x08: /* sense interrupt status */
+      /* execution:
+       *   get status
+       * result:
+       *   no interupt
+       *   byte0 = status reg0
+       *   byte1 = current cylinder number (0 to 79)
+       */
+      drive = BX_FD_THIS s.DOR & 0x03;
+      if (!BX_FD_THIS s.pending_irq) {
+        BX_FD_THIS s.status_reg0 = 0x80;
+        }
+      else {
+        if (BX_FD_THIS s.reset_sensei > 0) {
+          drive = 4 - BX_FD_THIS s.reset_sensei;
+          BX_FD_THIS s.status_reg0 &= 0xf8;
+          BX_FD_THIS s.status_reg0 |= (BX_FD_THIS s.head[drive] << 2) | drive;
+          BX_FD_THIS s.reset_sensei--;
+          }
+        }
+
+      BX_DEBUG(("sense interrupt status"));
+      enter_result_phase();
+      return;
+      break;
+
+    case 0x0f: /* seek */
+      /* command:
+       *   byte0 = 0F
+       *   byte1 = drive & head select
+       *   byte2 = cylinder number
+       * execution:
+       *   postion head over specified cylinder
+       * result:
+       *   no result bytes, issues an interrupt
+       */
+      drive = BX_FD_THIS s.command[1] & 0x03;
+      BX_FD_THIS s.DOR &= 0xfc;
+      BX_FD_THIS s.DOR |= drive;
+
+      BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+      BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.command[2];
+      /* ??? should also check cylinder validity */
+      bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+        bx_options.Ofloppy_command_delay->get (), 0 );
+      /* data reg not ready, drive busy */
+      BX_FD_THIS s.main_status_reg = (1 << drive);
+      return;
+      break;
+
+    case 0x13: // Configure
+      BX_DEBUG(("configure (eis     = 0x%02x)", BX_FD_THIS s.command[2] & 0x40 ));
+      BX_DEBUG(("configure (efifo   = 0x%02x)", BX_FD_THIS s.command[2] & 0x20 ));
+      BX_DEBUG(("configure (no poll = 0x%02x)", BX_FD_THIS s.command[2] & 0x10 ));
+      BX_DEBUG(("configure (fifothr = 0x%02x)", BX_FD_THIS s.command[2] & 0x0f ));
+      BX_DEBUG(("configure (pretrk  = 0x%02x)", BX_FD_THIS s.command[3] ));
+      enter_idle_phase();
+      return;
+      break;
+
+    case 0x4a: // read ID
+      drive = BX_FD_THIS s.command[1] & 0x03;
+      BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+      BX_FD_THIS s.DOR &= 0xfc;
+      BX_FD_THIS s.DOR |= drive;
+
+      motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+      if (motor_on == 0) {
+        BX_ERROR(("floppy_command(): 0x4a: motor not on"));
+        BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+        return;
+        }
+      if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+        BX_PANIC(("floppy_command(): read ID: bad drive #%d", drive));
+      BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive]<<2) | drive;
+      bx_pc_system.activate_timer( BX_FD_THIS s.floppy_timer_index,
+        bx_options.Ofloppy_command_delay->get (), 0 );
+      /* data reg not ready, controller busy */
+      BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+      return;
+      break;
+
+    case 0x4d: // format track
+        drive = BX_FD_THIS s.command[1] & 0x03;
+        BX_FD_THIS s.DOR &= 0xfc;
+        BX_FD_THIS s.DOR |= drive;
+
+        motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+        if (motor_on == 0)
+          BX_PANIC(("floppy_command(): format track: motor not on"));
+        BX_FD_THIS s.head[drive] = (BX_FD_THIS s.command[1] >> 2) & 0x01;
+        sector_size = BX_FD_THIS s.command[2];
+        BX_FD_THIS s.format_count = BX_FD_THIS s.command[3];
+        BX_FD_THIS s.format_fillbyte = BX_FD_THIS s.command[5];
+        if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+          BX_PANIC(("floppy_command(): format track: bad drive #%d", drive));
+
+        if (sector_size != 0x02) { // 512 bytes
+          BX_PANIC(("format track: sector size %d not supported", 128<<sector_size));
+          }
+        if (BX_FD_THIS s.format_count != BX_FD_THIS s.media[drive].sectors_per_track) {
+          BX_PANIC(("format track: %d sectors/track requested (%d expected)",
+                    BX_FD_THIS s.format_count, BX_FD_THIS s.media[drive].sectors_per_track));
+          }
+        if ( BX_FD_THIS s.media_present[drive] == 0 ) {
+          // media not in drive, return error
+          BX_INFO(("attempt to format track with media not present"));
+          BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+          BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+          BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+          enter_result_phase();
+          return;
+          }
+        if (BX_FD_THIS s.media[drive].write_protected) {
+          // media write-protected, return error
+          BX_INFO(("attempt to format track with media write-protected"));
+          BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+          BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+          BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+          enter_result_phase();
+          return;
+          }
+
+      /* 4 header bytes per sector are required */
+      BX_FD_THIS s.format_count <<= 2;
+
+      DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+      /* data reg not ready, controller busy */
+      BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+      BX_DEBUG(("format track"));
+      return;
+      break;
+
+    case 0x46: // read normal data, MT=0, SK=0
+    case 0x66: // read normal data, MT=0, SK=1
+    case 0xc6: // read normal data, MT=1, SK=0
+    case 0xe6: // read normal data, MT=1, SK=1
+    case 0x45: // write normal data, MT=0
+    case 0xc5: // write normal data, MT=1
+      BX_FD_THIS s.multi_track = (BX_FD_THIS s.command[0] >> 7);
+      if ( (BX_FD_THIS s.DOR & 0x08) == 0 )
+        BX_PANIC(("read/write command with DMA and int disabled"));
+      drive = BX_FD_THIS s.command[1] & 0x03;
+      BX_FD_THIS s.DOR &= 0xfc;
+      BX_FD_THIS s.DOR |= drive;
+
+      motor_on = (BX_FD_THIS s.DOR>>(drive+4)) & 0x01;
+      if (motor_on == 0)
+        BX_PANIC(("floppy_command(): read/write: motor not on"));
+      head = BX_FD_THIS s.command[3] & 0x01;
+      cylinder = BX_FD_THIS s.command[2]; /* 0..79 depending */
+      sector = BX_FD_THIS s.command[4];   /* 1..36 depending */
+      eot = BX_FD_THIS s.command[6];      /* 1..36 depending */
+      sector_size = BX_FD_THIS s.command[5];
+      data_length = BX_FD_THIS s.command[8];
+      BX_DEBUG(("read/write normal data"));
+      BX_DEBUG(("BEFORE"));
+      BX_DEBUG(("  drive    = %u", (unsigned) drive));
+      BX_DEBUG(("  head     = %u", (unsigned) head));
+      BX_DEBUG(("  cylinder = %u", (unsigned) cylinder));
+      BX_DEBUG(("  sector   = %u", (unsigned) sector));
+      BX_DEBUG(("  eot      = %u", (unsigned) eot));
+      if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+        BX_PANIC(("floppy_command(): read/write: bad drive #%d", drive));
+
+      // check that head number in command[1] bit two matches the head
+      // reported in the head number field.  Real floppy drives are
+      // picky about this, as reported in SF bug #439945, (Floppy drive
+      // read input error checking).
+      if (head != ((BX_FD_THIS s.command[1]>>2)&1)) {
+        BX_ERROR(("head number in command[1] doesn't match head field"));
+        BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+        BX_FD_THIS s.status_reg1 = 0x04; // 0000 0100
+        BX_FD_THIS s.status_reg2 = 0x00; // 0000 0000
+        enter_result_phase();
+        return;
+      }
+
+      if ( BX_FD_THIS s.media_present[drive] == 0 ) {
+        // media not in drive, return error
+
+        BX_INFO(("attempt to read/write sector %u,"
+                     " sectors/track=%u with media not present", 
+                     (unsigned) sector,
+                     (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+        BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive; // abnormal termination
+        BX_FD_THIS s.status_reg1 = 0x25; // 0010 0101
+        BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+        enter_result_phase();
+        return;
+        }
+
+      if (sector_size != 0x02) { // 512 bytes
+        BX_PANIC(("read/write command: sector size %d not supported", 128<<sector_size));
+        }
+      if ( cylinder >= BX_FD_THIS s.media[drive].tracks ) {
+        BX_PANIC(("io: norm r/w parms out of range: sec#%02xh cyl#%02xh eot#%02xh head#%02xh",
+          (unsigned) sector, (unsigned) cylinder, (unsigned) eot,
+          (unsigned) head));
+        return;
+      }
+
+      if (sector > BX_FD_THIS s.media[drive].sectors_per_track) {
+        // requested sector > last sector on track
+        BX_INFO(("attempt to read/write sector %u,"
+                     " sectors/track=%u", (unsigned) sector,
+                     (unsigned) BX_FD_THIS s.media[drive].sectors_per_track));
+        // set controller to where drive would have left off
+        // after it discovered the sector was past EOT
+        BX_FD_THIS s.cylinder[drive] = cylinder;
+        BX_FD_THIS s.head[drive]     = head;
+        BX_FD_THIS s.sector[drive]   = BX_FD_THIS s.media[drive].sectors_per_track;
+
+        // 0100 0HDD abnormal termination
+        BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+        // 1000 0101 end of cyl/NDAT/NID
+        BX_FD_THIS s.status_reg1 = 0x85;
+        // 0000 0000
+        BX_FD_THIS s.status_reg2 = 0x00;
+        enter_result_phase();
+        return;
+        }
+
+      if (cylinder != BX_FD_THIS s.cylinder[drive])
+        BX_DEBUG(("io: cylinder request != current cylinder"));
+
+        // original assumed all floppies had two sides...now it does not  *delete this comment line*
+        logical_sector = (cylinder * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+                       (head * BX_FD_THIS s.media[drive].sectors_per_track) +
+                       (sector - 1);
+
+      if (logical_sector >= BX_FD_THIS s.media[drive].sectors) {
+        BX_PANIC(("io: logical sector out of bounds"));
+        }
+
+      BX_FD_THIS s.cylinder[drive] = cylinder;
+      BX_FD_THIS s.sector[drive]   = sector;
+      BX_FD_THIS s.head[drive]     = head;
+
+      if ((BX_FD_THIS s.command[0] & 0x4f) == 0x46) { // read
+        floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+                    512, FROM_FLOPPY);
+
+        DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+        /* data reg not ready, controller busy */
+        BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+        return;
+        }
+      else if ((BX_FD_THIS s.command[0] & 0x7f) == 0x45) { // write
+
+        DEV_dma_set_drq(FLOPPY_DMA_CHAN, 1);
+
+        /* data reg not ready, controller busy */
+        BX_FD_THIS s.main_status_reg = FD_MS_BUSY;
+        return;
+        }
+      else
+        BX_PANIC(("floppy_command(): unknown read/write command"));
+
+      return;
+      break;
+
+    default: // invalid or unsupported command; these are captured in write() above
+      BX_PANIC(("You should never get here! cmd = 0x%02x", 
+                BX_FD_THIS s.command[0]));
+    }
+#endif
+}
+
+  void
+bx_floppy_ctrl_c::floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer,
+            Bit32u bytes, Bit8u direction)
+{
+  int ret;
+
+  if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE)
+    BX_PANIC(("floppy_xfer: bad drive #%d", drive));
+
+  if (bx_dbg.floppy) {
+    BX_INFO(("drive=%u", (unsigned) drive));
+    BX_INFO(("offset=%u", (unsigned) offset));
+    BX_INFO(("bytes=%u", (unsigned) bytes));
+    BX_INFO(("direction=%s", (direction==FROM_FLOPPY)? "from" : "to"));
+    }
+
+#if BX_WITH_MACOS
+  if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+    {
+    ret = lseek(BX_FD_THIS s.media[drive].fd, offset, SEEK_SET);
+    if (ret < 0) {
+      BX_PANIC(("could not perform lseek() on floppy image file"));
+      }
+    }
+
+  if (direction == FROM_FLOPPY) {
+#if BX_WITH_MACOS
+    if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+      ret = fd_read((char *) buffer, offset, bytes);
+    else
+#endif
+      ret = ::read(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+    if (ret < int(bytes)) {
+      /* ??? */
+      if (ret > 0) {
+        BX_INFO(("partial read() on floppy image returns %u/%u",
+          (unsigned) ret, (unsigned) bytes));
+        memset(buffer + ret, 0, bytes - ret);
+        }
+      else {
+        BX_INFO(("read() on floppy image returns 0"));
+        memset(buffer, 0, bytes);
+        }
+      }
+    }
+
+  else { // TO_FLOPPY
+    BX_ASSERT (!BX_FD_THIS s.media[drive].write_protected);
+#if BX_WITH_MACOS
+    if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+      ret = fd_write((char *) buffer, offset, bytes);
+    else
+#endif
+      ret = ::write(BX_FD_THIS s.media[drive].fd, (bx_ptr_t) buffer, bytes);
+    if (ret < int(bytes)) {
+      BX_PANIC(("could not perform write() on floppy image file"));
+    }
+  }
+}
+
+
+
+  void
+bx_floppy_ctrl_c::timer_handler(void *this_ptr)
+{
+
+  bx_floppy_ctrl_c *class_ptr = (bx_floppy_ctrl_c *) this_ptr;
+
+  class_ptr->timer();
+}
+
+  void
+bx_floppy_ctrl_c::timer()
+{
+  Bit8u drive;
+
+  drive = BX_FD_THIS s.DOR & 0x03;
+  switch ( BX_FD_THIS s.pending_command ) {
+    case 0x07: // recal
+    case 0x0f: // seek
+      BX_FD_THIS s.status_reg0 = 0x20 | (BX_FD_THIS s.head[drive]<<2) | drive;
+      if (BX_FD_THIS s.device_type[drive] == BX_FLOPPY_NONE) {
+        BX_FD_THIS s.status_reg0 |= 0x50;
+        }
+      else if (BX_FD_THIS s.media_present[drive] == 0) {
+        BX_FD_THIS s.status_reg0 |= 0x40;
+        BX_FD_THIS s.status_reg1 = 0x25;
+        BX_FD_THIS s.status_reg2 = 0x31;
+        }
+
+      /* reset changeline */
+      if (drive > 1) return;
+      if (BX_FD_THIS s.media_present[drive])
+        BX_FD_THIS s.DIR[drive] &= ~0x80; // clear disk change line
+
+      enter_idle_phase();
+      raise_interrupt();
+      break;
+
+    case 0x4a: /* read ID */
+      enter_result_phase();
+      break;
+
+    case 0xfe: // (contrived) RESET
+      theFloppyController->reset(BX_RESET_SOFTWARE);
+      BX_FD_THIS s.pending_command = 0;
+      BX_FD_THIS s.status_reg0 = 0xc0;
+      raise_interrupt();
+      BX_FD_THIS s.reset_sensei = 4;
+      break;
+    
+    case 0x00: // nothing pending?
+      break;
+
+    default:
+      BX_PANIC(("floppy:timer(): unknown case %02x",
+        (unsigned) BX_FD_THIS s.pending_command));
+    }
+  return;
+}
+
+  void
+bx_floppy_ctrl_c::dma_write(Bit8u *data_byte)
+{
+  // A DMA write is from I/O to Memory
+  // We need to return then next data byte from the floppy buffer
+  // to be transfered via the DMA to memory. (read block from floppy)
+
+
+  *data_byte = BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++];
+
+  if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+    Bit8u drive;
+
+    drive = BX_FD_THIS s.DOR & 0x03;
+    increment_sector(); // increment to next sector before retrieving next one
+    BX_FD_THIS s.floppy_buffer_index = 0;
+    if (DEV_dma_get_tc()) { // Terminal Count line, done
+      BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+      BX_FD_THIS s.status_reg1 = 0;
+      BX_FD_THIS s.status_reg2 = 0;
+
+      if (bx_dbg.floppy) {
+        BX_INFO(("<<READ DONE>>"));
+        BX_INFO(("AFTER"));
+        BX_INFO(("  drive    = %u", (unsigned) drive));
+        BX_INFO(("  head     = %u", (unsigned) BX_FD_THIS s.head[drive]));
+        BX_INFO(("  cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
+        BX_INFO(("  sector   = %u", (unsigned) BX_FD_THIS s.sector[drive]));
+        }
+
+      DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+      enter_result_phase();
+      }
+    else { // more data to transfer
+      Bit32u logical_sector;
+
+      // original assumed all floppies had two sides...now it does not  *delete this comment line*
+      logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads *
+                        BX_FD_THIS s.media[drive].sectors_per_track) +
+                       (BX_FD_THIS s.head[drive] *
+                        BX_FD_THIS s.media[drive].sectors_per_track) +
+                       (BX_FD_THIS s.sector[drive] - 1);
+
+      floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+                  512, FROM_FLOPPY);
+      }
+    }
+}
+
+  void
+bx_floppy_ctrl_c::dma_read(Bit8u *data_byte)
+{
+  // A DMA read is from Memory to I/O
+  // We need to write the data_byte which was already transfered from memory
+  // via DMA to I/O (write block to floppy)
+
+  Bit8u drive;
+  Bit32u logical_sector;
+
+  drive = BX_FD_THIS s.DOR & 0x03;
+  if (BX_FD_THIS s.pending_command == 0x4d) { // format track in progress
+    --BX_FD_THIS s.format_count;
+    switch (3 - (BX_FD_THIS s.format_count & 0x03)) {
+      case 0:
+        BX_FD_THIS s.cylinder[drive] = *data_byte;
+        break;
+      case 1:
+        if (*data_byte != BX_FD_THIS s.head[drive])
+          BX_ERROR(("head number does not match head field"));
+        break;
+      case 2:
+        BX_FD_THIS s.sector[drive] = *data_byte;
+        break;
+      case 3:
+        if (*data_byte != 2) BX_ERROR(("dma_read: sector size %d not supported", 128<<(*data_byte)));
+        BX_DEBUG(("formatting cylinder %u head %u sector %u",
+                  BX_FD_THIS s.cylinder[drive], BX_FD_THIS s.head[drive],
+                  BX_FD_THIS s.sector[drive]));
+        for (unsigned i = 0; i < 512; i++) {
+          BX_FD_THIS s.floppy_buffer[i] = BX_FD_THIS s.format_fillbyte;
+          }
+        // original assumed all floppies had two sides...now it does not *delete this comment line*
+        logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+                         (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+                         (BX_FD_THIS s.sector[drive] - 1);
+        floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+                    512, TO_FLOPPY);
+        break;
+      }
+    if ((BX_FD_THIS s.format_count == 0) || (DEV_dma_get_tc())) {
+      BX_FD_THIS s.format_count = 0;
+      BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+      DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+      enter_result_phase();
+      }
+    return;
+    }
+
+  BX_FD_THIS s.floppy_buffer[BX_FD_THIS s.floppy_buffer_index++] = *data_byte;
+
+  if (BX_FD_THIS s.floppy_buffer_index >= 512) {
+    // original assumed all floppies had two sides...now it does not *delete this comment line*
+    logical_sector = (BX_FD_THIS s.cylinder[drive] * BX_FD_THIS s.media[drive].heads * BX_FD_THIS s.media[drive].sectors_per_track) +
+                     (BX_FD_THIS s.head[drive] * BX_FD_THIS s.media[drive].sectors_per_track) +
+                     (BX_FD_THIS s.sector[drive] - 1);
+  if ( BX_FD_THIS s.media[drive].write_protected ) {
+    // write protected error
+    BX_INFO(("tried to write disk %u, which is write-protected", drive));
+    // ST0: IC1,0=01  (abnormal termination: started execution but failed)
+    BX_FD_THIS s.status_reg0 = 0x40 | (BX_FD_THIS s.head[drive]<<2) | drive;
+    // ST1: DataError=1, NDAT=1, NotWritable=1, NID=1
+    BX_FD_THIS s.status_reg1 = 0x27; // 0010 0111
+    // ST2: CRCE=1, SERR=1, BCYL=1, NDAM=1.
+    BX_FD_THIS s.status_reg2 = 0x31; // 0011 0001
+    enter_result_phase();
+    return;
+    }
+    floppy_xfer(drive, logical_sector*512, BX_FD_THIS s.floppy_buffer,
+                512, TO_FLOPPY);
+    increment_sector(); // increment to next sector after writing current one
+    BX_FD_THIS s.floppy_buffer_index = 0;
+    if (DEV_dma_get_tc()) { // Terminal Count line, done
+      BX_FD_THIS s.status_reg0 = (BX_FD_THIS s.head[drive] << 2) | drive;
+      BX_FD_THIS s.status_reg1 = 0;
+      BX_FD_THIS s.status_reg2 = 0;
+
+      if (bx_dbg.floppy) {
+        BX_INFO(("<<WRITE DONE>>"));
+        BX_INFO(("AFTER"));
+        BX_INFO(("  drive    = %u", (unsigned) drive));
+        BX_INFO(("  head     = %u", (unsigned) BX_FD_THIS s.head[drive]));
+        BX_INFO(("  cylinder = %u", (unsigned) BX_FD_THIS s.cylinder[drive]));
+        BX_INFO(("  sector   = %u", (unsigned) BX_FD_THIS s.sector[drive]));
+        }
+
+      DEV_dma_set_drq(FLOPPY_DMA_CHAN, 0);
+      enter_result_phase();
+      }
+    else { // more data to transfer
+      } // else
+    } // if BX_FD_THIS s.floppy_buffer_index >= 512
+}
+
+  void
+bx_floppy_ctrl_c::raise_interrupt(void)
+{
+  DEV_pic_raise_irq(6);
+  BX_FD_THIS s.pending_irq = 1;
+  BX_FD_THIS s.reset_sensei = 0;
+}
+
+
+  void
+bx_floppy_ctrl_c::increment_sector(void)
+{
+  Bit8u drive;
+
+  drive = BX_FD_THIS s.DOR & 0x03;
+
+  // values after completion of data xfer
+  // ??? calculation depends on base_count being multiple of 512
+  BX_FD_THIS s.sector[drive] ++;
+  if (BX_FD_THIS s.sector[drive] > BX_FD_THIS s.media[drive].sectors_per_track) {
+    BX_FD_THIS s.sector[drive] = 1;
+    if (BX_FD_THIS s.multi_track) {
+      BX_FD_THIS s.head[drive] ++;
+      if (BX_FD_THIS s.head[drive] > 1) {
+        BX_FD_THIS s.head[drive] = 0;
+        BX_FD_THIS s.cylinder[drive] ++;
+        }
+      }
+    else {
+      BX_FD_THIS s.cylinder[drive] ++;
+      }
+    if (BX_FD_THIS s.cylinder[drive] >= BX_FD_THIS s.media[drive].tracks) {
+      // Set to 1 past last possible cylinder value.
+      // I notice if I set it to tracks-1, prama linux won't boot.
+      BX_FD_THIS s.cylinder[drive] = BX_FD_THIS s.media[drive].tracks;
+      BX_INFO(("increment_sector: clamping cylinder to max"));
+      }
+    }
+}
+
+  unsigned
+bx_floppy_ctrl_c::set_media_status(unsigned drive, unsigned status)
+{
+  char *path;
+  unsigned type;
+
+  if (drive == 0)
+    type = bx_options.floppya.Otype->get ();
+  else
+    type = bx_options.floppyb.Otype->get ();
+
+  // if setting to the current value, nothing to do
+  if ((status == BX_FD_THIS s.media_present[drive]) &&
+      ((status == 0) || (type == BX_FD_THIS s.media[drive].type)))
+    return(status);
+
+  if (status == 0) {
+    // eject floppy
+    if (BX_FD_THIS s.media[drive].fd >= 0) {
+      close( BX_FD_THIS s.media[drive].fd );
+      BX_FD_THIS s.media[drive].fd = -1;
+      }
+    BX_FD_THIS s.media_present[drive] = 0;
+    if (drive == 0) {
+      bx_options.floppya.Ostatus->set(BX_EJECTED);
+    } else {
+      bx_options.floppyb.Ostatus->set(BX_EJECTED);
+    }
+    BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
+    return(0);
+    }
+  else {
+    // insert floppy
+    if (drive == 0) {
+      path = bx_options.floppya.Opath->getptr ();
+      }
+    else {
+      path = bx_options.floppyb.Opath->getptr ();
+      }
+    if (!strcmp(path, "none"))
+      return(0);
+    if (evaluate_media(type, path, & BX_FD_THIS s.media[drive])) {
+      BX_FD_THIS s.media_present[drive] = 1;
+      if (drive == 0) {
+#define MED (BX_FD_THIS s.media[0])
+        BX_INFO(("fd0: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppya.Opath->getptr(),
+        MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+        bx_options.floppya.Ostatus->set(BX_INSERTED);
+      } else {
+#define MED (BX_FD_THIS s.media[1])
+        BX_INFO(("fd1: '%s' ro=%d, h=%d,t=%d,spt=%d", bx_options.floppyb.Opath->getptr(),
+        MED.write_protected, MED.heads, MED.tracks, MED.sectors_per_track));
+#undef MED
+        bx_options.floppyb.Ostatus->set(BX_INSERTED);
+      }
+      BX_FD_THIS s.DIR[drive] |= 0x80; // disk changed line
+      return(1);
+      }
+    else {
+      BX_FD_THIS s.media_present[drive] = 0;
+      if (drive == 0) {
+        bx_options.floppya.Ostatus->set(BX_EJECTED);
+      } else {
+        bx_options.floppyb.Ostatus->set(BX_EJECTED);
+      }
+      return(0);
+      }
+    }
+}
+
+  unsigned
+bx_floppy_ctrl_c::get_media_status(unsigned drive)
+{
+  return( BX_FD_THIS s.media_present[drive] );
+}
+
+#ifdef O_BINARY
+#define BX_RDONLY O_RDONLY | O_BINARY
+#define BX_RDWR O_RDWR | O_BINARY
+#else
+#define BX_RDONLY O_RDONLY
+#define BX_RDWR O_RDWR
+#endif
+
+  bx_bool
+bx_floppy_ctrl_c::evaluate_media(unsigned type, char *path, floppy_t *media)
+{
+  struct stat stat_buf;
+  int i, ret;
+  int idx = -1;
+#ifdef __linux__
+  struct floppy_struct floppy_geom;
+#endif
+#ifdef WIN32
+  char sTemp[1024];
+  bx_bool raw_floppy = 0;
+  HANDLE hFile;
+  DWORD bytes;
+  DISK_GEOMETRY dg;
+  unsigned tracks, heads, spt;
+#endif
+
+  if (type == BX_FLOPPY_NONE)
+    return(0);
+
+  //If media file is already open, close it before reopening.
+  if(media->fd >=0) {
+    close(media->fd);
+    media->fd=-1;
+  }
+
+  // open media file (image file or device)
+  media->write_protected = 0;
+#ifdef macintosh
+  media->fd = 0;
+  if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+#ifdef WIN32
+    if ( (isalpha(path[0])) && (path[1] == ':') && (strlen(path) == 2) ) {
+      raw_floppy = 1;
+      wsprintf(sTemp, "\\\\.\\%s", path);
+      hFile = CreateFile(sTemp, GENERIC_READ, FILE_SHARE_WRITE, NULL,
+                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+      if (hFile == INVALID_HANDLE_VALUE) {
+        BX_ERROR(("Cannot open floppy drive"));
+        return(0);
+      } else {
+        if (!DeviceIoControl(hFile, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg), &bytes, NULL)) {
+          BX_ERROR(("No media in floppy drive"));
+          CloseHandle(hFile);
+          return(0);
+        } else {
+          tracks = (unsigned)dg.Cylinders.QuadPart;
+          heads  = (unsigned)dg.TracksPerCylinder;
+          spt    = (unsigned)dg.SectorsPerTrack;
+        }
+        CloseHandle(hFile);
+      }
+      media->fd = open(sTemp, BX_RDWR);
+    } else {
+      media->fd = open(path, BX_RDWR);
+    } 
+#else
+    media->fd = open(path, BX_RDWR);
+#endif
+
+  if (media->fd < 0) {
+    BX_INFO(( "tried to open '%s' read/write: %s",path,strerror(errno) ));
+    // try opening the file read-only
+    media->write_protected = 1;
+#ifdef macintosh
+  media->fd = 0;
+  if (strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+#endif
+#ifdef WIN32
+    if (raw_floppy == 1) {
+      media->fd = open(sTemp, BX_RDONLY);
+    } else {
+      media->fd = open(path, BX_RDONLY);
+    }
+#else
+    media->fd = open(path, BX_RDONLY);
+#endif
+    if (media->fd < 0) {
+      // failed to open read-only too
+      BX_INFO(( "tried to open '%s' read only: %s",path,strerror(errno) ));
+      media->type = type;
+      return(0);
+    }
+  }
+
+#if BX_WITH_MACOS
+  if (!strcmp(bx_options.floppya.Opath->getptr (), SuperDrive))
+    ret = fd_stat(&stat_buf);
+  else
+    ret = fstat(media->fd, &stat_buf);
+#elif defined(WIN32)
+  if (raw_floppy) {
+    memset (&stat_buf, 0, sizeof(stat_buf));
+    stat_buf.st_mode = S_IFCHR;
+    ret = 0;
+  } else {
+    ret = fstat(media->fd, &stat_buf);
+  }
+#else
+  // unix
+  ret = fstat(media->fd, &stat_buf);
+#endif
+  if (ret) {
+    BX_PANIC(("fstat floppy 0 drive image file returns error: %s", strerror(errno)));
+    return(0);
+    }
+
+  for (i = 0; i < 8; i++) {
+    if (type == floppy_type[i].id) idx = i;
+  }
+  if (idx == -1 ) {
+    BX_PANIC(("evaluate_media: unknown media type"));
+    return(0);
+  }
+  if ( S_ISREG(stat_buf.st_mode) ) {
+    // regular file
+    switch (type) {
+      // use CMOS reserved types
+      case BX_FLOPPY_160K: // 160K 5.25"
+      case BX_FLOPPY_180K: // 180K 5.25"
+      case BX_FLOPPY_320K: // 320K 5.25"
+      // standard floppy types
+      case BX_FLOPPY_360K: // 360K 5.25"
+      case BX_FLOPPY_720K: // 720K 3.5"
+      case BX_FLOPPY_1_2: // 1.2M 5.25"
+      case BX_FLOPPY_2_88: // 2.88M 3.5"
+        media->type              = type;
+        media->tracks            = floppy_type[idx].trk;
+        media->heads             = floppy_type[idx].hd;
+        media->sectors_per_track = floppy_type[idx].spt;
+        media->sectors           = floppy_type[idx].sectors;
+        if (stat_buf.st_size > (media->sectors * 512)) {
+          BX_INFO(("evaluate_media: size of file '%s' (%lu) too large for selected type",
+                   path, (unsigned long) stat_buf.st_size));
+          return(0);
+        }
+        break;
+      default: // 1.44M 3.5"
+        media->type              = type;
+        if (stat_buf.st_size <= 1474560) {
+          media->tracks            = floppy_type[idx].trk;
+          media->heads             = floppy_type[idx].hd;
+          media->sectors_per_track = floppy_type[idx].spt;
+          }
+        else if (stat_buf.st_size == 1720320) {
+          media->sectors_per_track = 21;
+          media->tracks            = 80;
+          media->heads             = 2;
+          }
+        else if (stat_buf.st_size == 1763328) {
+          media->sectors_per_track = 21;
+          media->tracks            = 82;
+          media->heads             = 2;
+          }
+        else {
+          BX_INFO(("evaluate_media: file '%s' of unknown size %lu",
+            path, (unsigned long) stat_buf.st_size));
+          return(0);
+          }
+        media->sectors = media->heads * media->tracks * media->sectors_per_track;
+      }
+    return(1); // success
+    }
+
+  else if ( S_ISCHR(stat_buf.st_mode)
+#if BX_WITH_MACOS == 0
+#ifdef S_ISBLK
+            || S_ISBLK(stat_buf.st_mode)
+#endif
+#endif
+           ) {
+    // character or block device
+    // assume media is formatted to typical geometry for drive
+    media->type              = type;
+#ifdef __linux__
+    if (ioctl(media->fd, FDGETPRM, &floppy_geom) < 0) {
+      BX_ERROR(("cannot determine media geometry"));
+      return(0);
+    }
+    media->tracks            = floppy_geom.track;
+    media->heads             = floppy_geom.head;
+    media->sectors_per_track = floppy_geom.sect;
+    media->sectors           = floppy_geom.size;
+#elif defined(WIN32)
+    media->tracks            = tracks;
+    media->heads             = heads;
+    media->sectors_per_track = spt;
+    media->sectors = media->heads * media->tracks * media->sectors_per_track;
+#else
+    media->tracks            = floppy_type[idx].trk;
+    media->heads             = floppy_type[idx].hd;
+    media->sectors_per_track = floppy_type[idx].spt;
+    media->sectors           = floppy_type[idx].sectors;
+#endif
+    return(1); // success
+    }
+  else {
+    // unknown file type
+    BX_INFO(("unknown mode type"));
+    return(0);
+    }
+}
+
+
+void
+bx_floppy_ctrl_c::enter_result_phase(void)
+{
+
+  Bit8u drive;
+
+  drive = BX_FD_THIS s.DOR & 0x03;
+
+  /* these are always the same */
+  BX_FD_THIS s.result_index = 0;
+  BX_FD_THIS s.main_status_reg = FD_MS_MRQ | FD_MS_DIO | FD_MS_BUSY;
+
+  /* invalid command */
+  if ((BX_FD_THIS s.status_reg0 & 0xc0) == 0x80) {
+    BX_FD_THIS s.result_size = 1;
+    BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+    return;
+  } 
+
+  switch (BX_FD_THIS s.pending_command) {
+  case 0x04: // get status
+    BX_FD_THIS s.result_size = 1;
+    BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg3;
+    break;
+  case 0x08: // sense interrupt
+    BX_FD_THIS s.result_size = 2;
+    BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;
+    BX_FD_THIS s.result[1] = BX_FD_THIS s.cylinder[drive];
+    break;
+  case 0x4a: // read ID
+  case 0x4d: // format track
+  case 0x46: // read normal data
+  case 0x66:
+  case 0xc6:
+  case 0xe6:
+  case 0x45: // write normal data
+  case 0xc5:
+    BX_FD_THIS s.result_size = 7;
+    BX_FD_THIS s.result[0] = BX_FD_THIS s.status_reg0;    
+    BX_FD_THIS s.result[1] = BX_FD_THIS s.status_reg1;
+    BX_FD_THIS s.result[2] = BX_FD_THIS s.status_reg2;
+    BX_FD_THIS s.result[3] = BX_FD_THIS s.cylinder[drive];
+    BX_FD_THIS s.result[4] = BX_FD_THIS s.head[drive];
+    BX_FD_THIS s.result[5] = BX_FD_THIS s.sector[drive];
+    BX_FD_THIS s.result[6] = 2; /* sector size code */
+    raise_interrupt();
+    break;
+  }
+}
+
+void
+bx_floppy_ctrl_c::enter_idle_phase(void)
+{
+  BX_FD_THIS s.main_status_reg &= 0x0f;      // leave drive status untouched
+  BX_FD_THIS s.main_status_reg |= FD_MS_MRQ; // data register ready
+
+  BX_FD_THIS s.command_complete = 1; /* waiting for new command */
+  BX_FD_THIS s.command_index = 0;
+  BX_FD_THIS s.command_size = 0;
+  BX_FD_THIS s.pending_command = 0;
+
+  BX_FD_THIS s.floppy_buffer_index = 0;
+}
+
diff --git a/tools/ioemu/iodev/floppy.h b/tools/ioemu/iodev/floppy.h
new file mode 100644 (file)
index 0000000..d874539
--- /dev/null
@@ -0,0 +1,138 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: floppy.h,v 1.16 2002/11/30 09:39:29 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#define FROM_FLOPPY 10
+#define TO_FLOPPY   11
+
+#if BX_USE_FD_SMF
+#  define BX_FD_SMF  static
+#  define BX_FD_THIS theFloppyController->
+#else
+#  define BX_FD_SMF
+#  define BX_FD_THIS this->
+#endif
+
+typedef struct {
+  int      fd;         /* file descriptor of floppy image file */
+  unsigned sectors_per_track;    /* number of sectors/track */
+  unsigned sectors;    /* number of formatted sectors on diskette */
+  unsigned tracks;      /* number of tracks */
+  unsigned heads;      /* number of heads */
+  unsigned type;
+  unsigned write_protected;
+  } floppy_t;
+
+class bx_floppy_ctrl_c : public bx_floppy_stub_c {
+public:
+
+  bx_floppy_ctrl_c(void);
+  ~bx_floppy_ctrl_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+  virtual unsigned set_media_status(unsigned drive, unsigned status);
+  virtual unsigned get_media_status(unsigned drive);
+
+private:
+
+  struct {
+    Bit8u   data_rate;
+
+    Bit8u   command[10]; /* largest command size ??? */
+    Bit8u   command_index;
+    Bit8u   command_size;
+    bx_bool command_complete;
+    Bit8u   pending_command;
+
+    bx_bool multi_track;
+    bx_bool pending_irq;
+    Bit8u   reset_sensei;
+    Bit8u   format_count;
+    Bit8u   format_fillbyte;
+
+    Bit8u   result[10];
+    Bit8u   result_index;
+    Bit8u   result_size;
+
+    Bit8u   DOR; // Digital Ouput Register
+    Bit8u   TDR; // Tape Drive Register
+    Bit8u   cylinder[4]; // really only using 2 drives
+    Bit8u   head[4];     // really only using 2 drives
+    Bit8u   sector[4];   // really only using 2 drives
+
+    /* MAIN STATUS REGISTER
+     * b7: MRQ: main request 1=data register ready     0=data register not ready
+     * b6: DIO: data input/output:
+     *     1=controller->CPU (ready for data read)
+     *     0=CPU->controller (ready for data write)
+     * b5: NDMA: non-DMA mode: 1=controller not in DMA modes
+     *                         0=controller in DMA mode
+     * b4: BUSY: instruction(device busy) 1=active 0=not active
+     * b3-0: ACTD, ACTC, ACTB, ACTA:
+     *       drive D,C,B,A in positioning mode 1=active 0=not active
+     */
+    Bit8u   main_status_reg;
+
+    Bit8u   status_reg0;
+    Bit8u   status_reg1;
+    Bit8u   status_reg2;
+    Bit8u   status_reg3;
+
+    // drive field allows up to 4 drives, even though probably only 2 will
+    // ever be used.
+    floppy_t media[4];
+    unsigned num_supported_floppies;
+    Bit8u    floppy_buffer[512+2]; // 2 extra for good measure
+    unsigned floppy_buffer_index;
+    int      floppy_timer_index;
+    bx_bool  media_present[2];
+    Bit8u    device_type[4];
+    Bit8u    DIR[4]; // Digital Input Register:
+                  // b7: 0=diskette is present and has not been changed
+                  //     1=diskette missing or changed
+    } s;  // state information
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_FD_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+  BX_FD_SMF void   dma_write(Bit8u *data_byte);
+  BX_FD_SMF void   dma_read(Bit8u *data_byte);
+  BX_FD_SMF void   floppy_command(void);
+  BX_FD_SMF void   floppy_xfer(Bit8u drive, Bit32u offset, Bit8u *buffer, Bit32u bytes, Bit8u direction);
+  BX_FD_SMF void   raise_interrupt(void);
+  BX_FD_SMF void   enter_idle_phase(void);
+  BX_FD_SMF void   enter_result_phase(void);
+  static void   timer_handler(void *);
+
+public:
+  BX_FD_SMF void   timer(void);
+  BX_FD_SMF void   increment_sector(void);
+  BX_FD_SMF bx_bool evaluate_media(unsigned type, char *path, floppy_t *floppy);
+  };
diff --git a/tools/ioemu/iodev/gameport.cc b/tools/ioemu/iodev/gameport.cc
new file mode 100644 (file)
index 0000000..9adefa6
--- /dev/null
@@ -0,0 +1,242 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gameport.cc,v 1.5 2003/12/29 21:48:56 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// Standard PC gameport
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#ifdef __linux__
+
+#include <linux/joystick.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#elif defined(WIN32)
+
+#ifndef JOY_BUTTON1
+#define JOY_BUTTON1 1
+#define JOY_BUTTON2 2
+UINT STDCALL joyGetPos(UINT, LPJOYINFO);
+#endif
+
+#define JOYSTICKID1 0
+
+#endif
+
+#define LOG_THIS theGameport->
+
+bx_gameport_c *theGameport = NULL;
+
+  int
+libgameport_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theGameport = new bx_gameport_c ();
+  bx_devices.pluginGameport = theGameport;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theGameport, BX_PLUGIN_GAMEPORT);
+  return(0); // Success
+}
+
+  void
+libgameport_LTX_plugin_fini(void)
+{
+}
+
+bx_gameport_c::bx_gameport_c(void)
+{
+  put("GAME");
+  settype(EXTFPUIRQLOG);
+}
+
+bx_gameport_c::~bx_gameport_c(void)
+{
+  if (joyfd >= 0) close(joyfd);
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_gameport_c::init(void)
+{
+  // Allocate the gameport IO address range 0x200..0x207
+  for (unsigned addr=0x200; addr<0x208; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "Gameport", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "Gameport", 1);
+  }
+
+  BX_GAMEPORT_THIS port = 0xf0;
+  BX_GAMEPORT_THIS write_usec = 0;
+  BX_GAMEPORT_THIS timer_x = 0;
+  BX_GAMEPORT_THIS timer_y = 0;
+
+#ifdef __linux__
+  BX_GAMEPORT_THIS joyfd = open("/dev/input/js0", O_RDONLY);
+  if (BX_GAMEPORT_THIS joyfd >= 0) {
+    for (unsigned i=0; i<4; i++) poll_joydev();
+  }
+#elif defined(WIN32)
+  JOYINFO joypos;
+  if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
+    BX_GAMEPORT_THIS joyfd = 1;
+  } else {
+    BX_GAMEPORT_THIS joyfd = -1;
+  }
+#else
+  BX_GAMEPORT_THIS joyfd = -1;
+#endif
+}
+
+  void
+bx_gameport_c::reset(unsigned type)
+{
+  // nothing for now
+}
+
+  void
+bx_gameport_c::poll_joydev(void)
+{
+#ifdef __linux__
+  struct js_event e;
+  fd_set joyfds;
+  struct timeval tv;
+
+  memset(&tv, 0, sizeof(tv));
+  FD_ZERO(&joyfds);
+  FD_SET(BX_GAMEPORT_THIS joyfd, &joyfds);
+  e.type = 0;
+  if (select(BX_GAMEPORT_THIS joyfd+1, &joyfds, NULL, NULL, &tv)) {
+    read(BX_GAMEPORT_THIS joyfd, &e, sizeof(struct js_event));
+    if (e.type & JS_EVENT_BUTTON) {
+      if (e.value == 1) {
+        BX_GAMEPORT_THIS port &= ~(0x10 << e.number);
+      } else {
+        BX_GAMEPORT_THIS port |= (0x10 << e.number);
+      }
+    }
+    if (e.type & JS_EVENT_AXIS) {
+      if (e.number == 0) {
+        BX_GAMEPORT_THIS delay_x = 25 + ((e.value + 0x8000) / 60);
+      }
+      if (e.number == 1) {
+        BX_GAMEPORT_THIS delay_y = 25 + ((e.value + 0x8000) / 62);
+      }
+    }
+  }
+#elif defined(WIN32)
+  JOYINFO joypos;
+  if (joyGetPos(JOYSTICKID1, &joypos) == JOYERR_NOERROR) {
+    if (joypos.wButtons & JOY_BUTTON1) {
+      BX_GAMEPORT_THIS port &= ~0x10;
+    } else {
+      BX_GAMEPORT_THIS port |= 0x10;
+    }
+    if (joypos.wButtons & JOY_BUTTON2) {
+      BX_GAMEPORT_THIS port &= ~0x20;
+    } else {
+      BX_GAMEPORT_THIS port |= 0x20;
+    }
+    BX_GAMEPORT_THIS delay_x = 25 + (joypos.wXpos / 60);
+    BX_GAMEPORT_THIS delay_y = 25 + (joypos.wYpos / 60);
+  }
+#endif
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_gameport_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_GAME_SMF
+  bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_gameport_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_GAME_SMF
+  Bit64u usec;
+
+  if (BX_GAMEPORT_THIS joyfd >= 0) {
+    poll_joydev();
+    usec = bx_pc_system.time_usec();
+    if (BX_GAMEPORT_THIS timer_x) {
+      if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_x) {
+        BX_GAMEPORT_THIS port &= 0xfe;
+        BX_GAMEPORT_THIS timer_x = 0;
+      }
+    }
+    if (BX_GAMEPORT_THIS timer_y) {
+      if ((usec - BX_GAMEPORT_THIS write_usec) >= BX_GAMEPORT_THIS delay_y) {
+        BX_GAMEPORT_THIS port &= 0xfd;
+        BX_GAMEPORT_THIS timer_y = 0;
+      }
+    }
+  } else {
+    BX_DEBUG(("read: joystick not present"));
+  }
+  return BX_GAMEPORT_THIS port;
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_gameport_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_GAME_SMF
+  bx_gameport_c *class_ptr = (bx_gameport_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_gameport_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_GAME_SMF
+
+  BX_GAMEPORT_THIS write_usec = bx_pc_system.time_usec();
+  BX_GAMEPORT_THIS timer_x = 1;
+  BX_GAMEPORT_THIS timer_y = 1;
+  BX_GAMEPORT_THIS port |= 0x0f;
+}
diff --git a/tools/ioemu/iodev/gameport.h b/tools/ioemu/iodev/gameport.h
new file mode 100644 (file)
index 0000000..d4acddd
--- /dev/null
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: gameport.h,v 1.1 2003/06/21 12:55:19 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#if BX_USE_GAME_SMF
+#  define BX_GAMEPORT_SMF  static
+#  define BX_GAMEPORT_THIS theGameport->
+#else
+#  define BX_GAMEPORT_SMF
+#  define BX_GAMEPORT_THIS this->
+#endif
+
+
+class bx_gameport_c : public bx_devmodel_c {
+
+public:
+  bx_gameport_c(void);
+  ~bx_gameport_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+
+  int     joyfd;
+  Bit8u   port;
+  Bit16u  delay_x;
+  Bit16u  delay_y;
+  bx_bool timer_x;
+  bx_bool timer_y;
+  Bit64u  write_usec;
+
+  BX_GAMEPORT_SMF void poll_joydev(void);
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_GAME_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+  };
diff --git a/tools/ioemu/iodev/guest2host.h b/tools/ioemu/iodev/guest2host.h
new file mode 100644 (file)
index 0000000..0003662
--- /dev/null
@@ -0,0 +1,77 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: guest2host.h,v 1.8 2002/12/06 18:48:08 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#define BX_MAX_G2H_CHANNELS 8
+#define BX_G2H_ERROR        ((unsigned) -1)
+  // IO port number for this interface.  Align on dword boundary.
+#define BX_G2H_PORT  0x2000
+  // Magic number which is first dword passed by guest
+#define BX_G2H_MAGIC 0xffeeddcc
+  // Number of dwords in packet from guest
+#define BX_G2H_PACKET_SIZE 5
+
+
+
+typedef Bit32u bx_guest_packet_t[BX_G2H_PACKET_SIZE];
+typedef void (*bx_g2h_callback_t)(bx_guest_packet_t *);
+
+
+
+class bx_g2h_c : public logfunctions {
+public:
+  bx_g2h_c(void);
+  ~bx_g2h_c(void);
+  static void   init(void);
+  void reset (unsigned type);
+  unsigned acquire_channel(bx_g2h_callback_t);
+  unsigned deacquire_channel(unsigned channel);
+
+private:
+
+  static Bit32u inp_handler(void *this_ptr, Bit32u addr, unsigned io_len);
+  static void   outp_handler(void *this_ptr, Bit32u addr,
+                              Bit32u value, unsigned io_len);
+  // state info
+  struct {
+    struct {
+      bx_g2h_callback_t f;
+      bx_bool used;
+      } callback[BX_MAX_G2H_CHANNELS];
+
+    // Define the data received from the guest OS.
+    //   dword0: magic number, should be BX_G2H_MAGIC
+    //   dword1: channel ID
+    //   dword2: address of data structure in guest physical memory
+    //   dword3: size of data structure in guest physical memory
+    //   dword4: address of return data structure in guest physical memory
+    unsigned packet_count;
+    bx_guest_packet_t guest_packet;
+    } s;
+  };
+
+extern bx_g2h_c bx_g2h;
diff --git a/tools/ioemu/iodev/harddrv.cc b/tools/ioemu/iodev/harddrv.cc
new file mode 100644 (file)
index 0000000..24a9d41
--- /dev/null
@@ -0,0 +1,4880 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: harddrv.cc,v 1.114.2.2 2004/02/06 22:14:35 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Useful docs:
+// AT Attachment with Packet Interface
+// working draft by T13 at www.t13.org
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#if BX_HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#define LOG_THIS theHardDrive->
+
+// WARNING: dangerous options!
+// These options provoke certain kinds of errors for testing purposes when they
+// are set to a nonzero value.  DO NOT ENABLE THEM when using any disk image
+// you care about.
+#define TEST_READ_BEYOND_END 0
+#define TEST_WRITE_BEYOND_END 0
+#ifdef __GNUC__
+#  if TEST_READ_BEYOND_END || TEST_WRITE_BEYOND_END
+#    warning BEWARE: Dangerous options are enabled in harddrv.cc. If you are not trying to provoke hard drive errors you should disable them right now.
+#  endif
+#endif
+// end of dangerous options.
+
+
+#define INDEX_PULSE_CYCLE 10
+
+#define PACKET_SIZE 12
+
+static unsigned max_multiple_sectors  = 0; // was 0x3f
+static unsigned curr_multiple_sectors = 0; // was 0x3f
+
+// some packet handling macros
+#define EXTRACT_FIELD(arr,byte,start,num_bits) (((arr)[(byte)] >> (start)) & ((1 << (num_bits)) - 1))
+#define get_packet_field(c,b,s,n) (EXTRACT_FIELD((BX_SELECTED_CONTROLLER((c)).buffer),(b),(s),(n)))
+#define get_packet_byte(c,b) (BX_SELECTED_CONTROLLER((c)).buffer[(b)])
+#define get_packet_word(c,b) (((uint16)BX_SELECTED_CONTROLLER((c)).buffer[(b)] << 8) | BX_SELECTED_CONTROLLER((c)).buffer[(b)+1])
+
+
+#define BX_CONTROLLER(c,a) (BX_HD_THIS channels[(c)].drives[(a)]).controller
+#define BX_DRIVE(c,a) (BX_HD_THIS channels[(c)].drives[(a)])
+
+#define BX_DRIVE_IS_PRESENT(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type != IDE_NONE)
+#define BX_DRIVE_IS_HD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_DISK)
+#define BX_DRIVE_IS_CD(c,a) (BX_HD_THIS channels[(c)].drives[(a)].device_type == IDE_CDROM)
+
+#define BX_MASTER_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),0)
+#define BX_SLAVE_IS_PRESENT(c) BX_DRIVE_IS_PRESENT((c),1)
+#define BX_ANY_IS_PRESENT(c) (BX_DRIVE_IS_PRESENT((c),0) || BX_DRIVE_IS_PRESENT((c),1))
+
+#define BX_SELECTED_CONTROLLER(c) (BX_CONTROLLER((c),BX_HD_THIS channels[(c)].drive_select))
+#define BX_SELECTED_DRIVE(c) (BX_DRIVE((c),BX_HD_THIS channels[(c)].drive_select))
+#define BX_MASTER_SELECTED(c) (!BX_HD_THIS channels[(c)].drive_select)
+#define BX_SLAVE_SELECTED(c)  (BX_HD_THIS channels[(c)].drive_select)
+
+#define BX_SELECTED_IS_PRESENT(c) (BX_DRIVE_IS_PRESENT((c),BX_SLAVE_SELECTED((c))))
+#define BX_SELECTED_IS_HD(c) (BX_DRIVE_IS_HD((c),BX_SLAVE_SELECTED((c))))
+#define BX_SELECTED_IS_CD(c) (BX_DRIVE_IS_CD((c),BX_SLAVE_SELECTED((c))))
+
+#define BX_SELECTED_MODEL(c) (BX_HD_THIS channels[(c)].drives[BX_HD_THIS channels[(c)].drive_select].model_no)
+#define BX_SELECTED_TYPE_STRING(channel) ((BX_SELECTED_IS_CD(channel)) ? "CD-ROM" : "DISK")
+
+#define WRITE_FEATURES(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).features = _a; BX_CONTROLLER((c),1).features = _a; } while(0)
+#define WRITE_SECTOR_COUNT(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_count = _a; BX_CONTROLLER((c),1).sector_count = _a; } while(0)
+#define WRITE_SECTOR_NUMBER(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).sector_no = _a; BX_CONTROLLER((c),1).sector_no = _a; } while(0)
+#define WRITE_CYLINDER_LOW(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).cylinder_no = (BX_CONTROLLER((c),0).cylinder_no & 0xff00) | _a; BX_CONTROLLER((c),1).cylinder_no = (BX_CONTROLLER((c),1).cylinder_no & 0xff00) | _a; } while(0)
+#define WRITE_CYLINDER_HIGH(c,a) do { uint16 _a = a; BX_CONTROLLER((c),0).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),0).cylinder_no & 0xff); BX_CONTROLLER((c),1).cylinder_no = (_a << 8) | (BX_CONTROLLER((c),1).cylinder_no & 0xff); } while(0)
+#define WRITE_HEAD_NO(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).head_no = _a; BX_CONTROLLER((c),1).head_no = _a; } while(0)
+#define WRITE_LBA_MODE(c,a) do { uint8 _a = a; BX_CONTROLLER((c),0).lba_mode = _a; BX_CONTROLLER((c),1).lba_mode = _a; } while(0)
+
+bx_hard_drive_c *theHardDrive = NULL;
+
+  int
+libharddrv_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theHardDrive = new bx_hard_drive_c ();
+  bx_devices.pluginHardDrive = theHardDrive;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theHardDrive, BX_PLUGIN_HARDDRV);
+  return(0); // Success
+}
+
+  void
+libharddrv_LTX_plugin_fini(void)
+{
+}
+
+bx_hard_drive_c::bx_hard_drive_c(void)
+{
+#if DLL_HD_SUPPORT
+#   error code must be fixed to use DLL_HD_SUPPORT and 4 ata channels
+#endif
+
+    for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+      channels[channel].drives[0].hard_drive =  NULL;
+      channels[channel].drives[1].hard_drive =  NULL;
+      put("HD");
+      settype(HDLOG);
+    }
+}
+
+
+bx_hard_drive_c::~bx_hard_drive_c(void)
+{
+       BX_DEBUG(("Exit."));
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if (channels[channel].drives[0].hard_drive != NULL )      /* DT 17.12.2001 21:55 */
+    {
+      delete channels[channel].drives[0].hard_drive;
+      channels[channel].drives[0].hard_drive =  NULL;
+    }
+    if ( channels[channel].drives[1].hard_drive != NULL )
+    {
+      delete channels[channel].drives[1].hard_drive;
+      channels[channel].drives[1].hard_drive =  NULL;        /* DT 17.12.2001 21:56 */
+    }
+  }
+}
+
+
+
+
+  void
+bx_hard_drive_c::init(void)
+{
+  Bit8u channel;
+  char  string[5];
+
+  BX_DEBUG(("Init $Id: harddrv.cc,v 1.114.2.2 2004/02/06 22:14:35 danielg4 Exp $"));
+
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if (bx_options.ata[channel].Opresent->get() == 1) {
+      BX_HD_THIS channels[channel].ioaddr1 = bx_options.ata[channel].Oioaddr1->get();
+      BX_HD_THIS channels[channel].ioaddr2 = bx_options.ata[channel].Oioaddr2->get();
+      BX_HD_THIS channels[channel].irq = bx_options.ata[channel].Oirq->get();
+
+      // Coherency check
+      if ( (BX_HD_THIS channels[channel].ioaddr1 == 0) ||
+           (BX_HD_THIS channels[channel].ioaddr2 == 0) ||
+           (BX_HD_THIS channels[channel].irq == 0) ) {
+        BX_PANIC(("incoherency for ata channel %d: io1=0x%x, io2=%x, irq=%d",
+         channel,
+         BX_HD_THIS channels[channel].ioaddr1,
+         BX_HD_THIS channels[channel].ioaddr2,
+         BX_HD_THIS channels[channel].irq));
+        }
+      }
+    else {
+      BX_HD_THIS channels[channel].ioaddr1 = 0;
+      BX_HD_THIS channels[channel].ioaddr2 = 0;
+      BX_HD_THIS channels[channel].irq = 0;
+      }
+    }
+
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    sprintf(string ,"ATA%d", channel);
+
+    if (BX_HD_THIS channels[channel].irq != 0) 
+      DEV_register_irq(BX_HD_THIS channels[channel].irq, strdup(string));
+
+    if (BX_HD_THIS channels[channel].ioaddr1 != 0) {
+      DEV_register_ioread_handler(this, read_handler,
+                           BX_HD_THIS channels[channel].ioaddr1, strdup(string), 6);
+      DEV_register_iowrite_handler(this, write_handler,
+                           BX_HD_THIS channels[channel].ioaddr1, strdup(string), 6);
+      for (unsigned addr=0x1; addr<=0x7; addr++) {
+        DEV_register_ioread_handler(this, read_handler,
+                             BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string), 1);
+        DEV_register_iowrite_handler(this, write_handler,
+                             BX_HD_THIS channels[channel].ioaddr1+addr, strdup(string), 1);
+        }
+      }
+
+    // We don't want to register addresses 0x3f6 and 0x3f7 as they are handled by the floppy controller
+    if ((BX_HD_THIS channels[channel].ioaddr2 != 0) && (BX_HD_THIS channels[channel].ioaddr2 != 0x3f0)) {
+      for (unsigned addr=0x6; addr<=0x7; addr++) {
+        DEV_register_ioread_handler(this, read_handler,
+                              BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string), 1);
+        DEV_register_iowrite_handler(this, write_handler,
+                              BX_HD_THIS channels[channel].ioaddr2+addr, strdup(string), 1);
+        }
+      }
+     
+     BX_HD_THIS channels[channel].drive_select = 0;
+    }
+
+  channel = 0;
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    for (Bit8u device=0; device<2; device ++) {
+
+         // Initialize controller state, even if device is not present
+      BX_CONTROLLER(channel,device).status.busy           = 0;
+      BX_CONTROLLER(channel,device).status.drive_ready    = 1;
+      BX_CONTROLLER(channel,device).status.write_fault    = 0;
+      BX_CONTROLLER(channel,device).status.seek_complete  = 1;
+      BX_CONTROLLER(channel,device).status.drq            = 0;
+      BX_CONTROLLER(channel,device).status.corrected_data = 0;
+      BX_CONTROLLER(channel,device).status.index_pulse    = 0;
+      BX_CONTROLLER(channel,device).status.index_pulse_count = 0;
+      BX_CONTROLLER(channel,device).status.err            = 0;
+
+      BX_CONTROLLER(channel,device).error_register = 0x01; // diagnostic code: no error
+      BX_CONTROLLER(channel,device).head_no        = 0;
+      BX_CONTROLLER(channel,device).sector_count   = 1;
+      BX_CONTROLLER(channel,device).sector_no      = 1;
+      BX_CONTROLLER(channel,device).cylinder_no    = 0;
+      BX_CONTROLLER(channel,device).current_command = 0x00;
+      BX_CONTROLLER(channel,device).buffer_index = 0;
+
+      BX_CONTROLLER(channel,device).control.reset       = 0;
+      BX_CONTROLLER(channel,device).control.disable_irq = 0;
+      BX_CONTROLLER(channel,device).reset_in_progress   = 0;
+
+      BX_CONTROLLER(channel,device).sectors_per_block   = 0x80;
+      BX_CONTROLLER(channel,device).lba_mode            = 0;
+      
+         BX_CONTROLLER(channel,device).features            = 0;
+       
+         // If not present
+      BX_HD_THIS channels[channel].drives[device].device_type           = IDE_NONE;
+      if (!bx_options.atadevice[channel][device].Opresent->get()) {
+        continue;
+        }
+
+      // Make model string
+      strncpy((char*)BX_HD_THIS channels[channel].drives[device].model_no, 
+        bx_options.atadevice[channel][device].Omodel->getptr(), 40);
+      while (strlen((char *)BX_HD_THIS channels[channel].drives[device].model_no) < 40) {
+        strcat ((char*)BX_HD_THIS channels[channel].drives[device].model_no, " ");
+        }
+
+      if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_DISK) {
+        BX_DEBUG(( "Hard-Disk on target %d/%d",channel,device));
+        BX_HD_THIS channels[channel].drives[device].device_type           = IDE_DISK;
+
+        int cyl = bx_options.atadevice[channel][device].Ocylinders->get ();
+        int heads = bx_options.atadevice[channel][device].Oheads->get ();
+        int spt = bx_options.atadevice[channel][device].Ospt->get ();
+        Bit64u disk_size = (Bit64u)cyl * heads * spt * 512;
+
+        /* instantiate the right class */
+        switch (bx_options.atadevice[channel][device].Omode->get()) {
+
+          case BX_ATA_MODE_FLAT:
+            BX_INFO(("HD on ata%d-%d: '%s' 'flat' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new default_image_t();
+            break;
+
+          case BX_ATA_MODE_CONCAT:
+            BX_INFO(("HD on ata%d-%d: '%s' 'concat' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new concat_image_t();
+            break;
+
+#if EXTERNAL_DISK_SIMULATOR
+          case BX_ATA_MODE_EXTDISKSIM:
+            BX_INFO(("HD on ata%d-%d: '%s' 'External Simulator' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new EXTERNAL_DISK_SIMULATOR_CLASS();
+            break;
+#endif //EXTERNAL_DISK_SIMULATOR
+
+#if DLL_HD_SUPPORT
+          case BX_ATA_MODE_DLL_HD:
+            BX_INFO(("HD on ata%d-%d: '%s' 'dll' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new dll_image_t();
+            break;
+#endif //DLL_HD_SUPPORT
+
+          case BX_ATA_MODE_SPARSE:
+            BX_INFO(("HD on ata%d-%d: '%s' 'sparse' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new sparse_image_t();
+            break;
+
+#if 0
+          case BX_ATA_MODE_VMWARE3:
+            BX_INFO(("HD on ata%d-%d: '%s' 'vmware3' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new vmware3_image_t();
+            break;
+
+          case BX_ATA_MODE_SPLIT:
+            BX_INFO(("HD on ata%d-%d: '%s' 'split' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new split_image_t();
+            break;
+#endif
+
+          case BX_ATA_MODE_UNDOABLE:
+            BX_INFO(("HD on ata%d-%d: '%s' 'undoable' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new undoable_image_t(disk_size,
+                            bx_options.atadevice[channel][device].Ojournal->getptr());
+            break;
+
+          case BX_ATA_MODE_GROWING:
+            BX_INFO(("HD on ata%d-%d: '%s' 'growing' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new growing_image_t(disk_size);
+            break;
+
+          case BX_ATA_MODE_VOLATILE:
+            BX_INFO(("HD on ata%d-%d: '%s' 'volatile' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new volatile_image_t(disk_size,
+                            bx_options.atadevice[channel][device].Ojournal->getptr());
+            break;
+
+#if 0
+#if BX_COMPRESSED_HD_SUPPORT
+          case BX_ATA_MODE_Z_UNDOABLE:
+            BX_PANIC(("z-undoable disk support not implemented"));
+            BX_INFO(("HD on ata%d-%d: '%s' 'z-undoable' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new z_undoable_image_t(disk_size,
+                            bx_options.atadevice[channel][device].Ojournal->getptr());
+            break;
+
+          case BX_ATA_MODE_Z_VOLATILE:
+            BX_PANIC(("z-volatile disk support not implemented"));
+            BX_INFO(("HD on ata%d-%d: '%s' 'z-volatile' mode ", channel, device, 
+                                    bx_options.atadevice[channel][device].Opath->getptr ()));
+            channels[channel].drives[device].hard_drive = new z_volatile_image_t(disk_size,
+                            bx_options.atadevice[channel][device].Ojournal->getptr());
+            break;
+#endif //BX_COMPRESSED_HD_SUPPORT
+#endif
+
+          default:
+            BX_PANIC(("HD on ata%d-%d: '%s' unsupported HD mode : %s", channel, device, 
+                      bx_options.atadevice[channel][device].Opath->getptr (),
+                      atadevice_mode_names[bx_options.atadevice[channel][device].Omode->get()]));
+            break;
+        }
+
+        BX_HD_THIS channels[channel].drives[device].hard_drive->cylinders = cyl;
+        BX_HD_THIS channels[channel].drives[device].hard_drive->heads = heads;
+        BX_HD_THIS channels[channel].drives[device].hard_drive->sectors = spt;
+
+        if (cyl == 0 || heads == 0 || spt == 0) {
+          BX_PANIC(("ata%d/%d cannot have zero cylinders, heads, or sectors/track", channel, device));
+          }
+
+        /* open hard drive image file */
+        if ((BX_HD_THIS channels[channel].drives[device].hard_drive->open(bx_options.atadevice[channel][device].Opath->getptr ())) < 0) {
+          BX_PANIC(("ata%d-%d: could not open hard drive image file '%s'", channel, device, bx_options.atadevice[channel][device].Opath->getptr ()));
+          }
+        }
+      else if (bx_options.atadevice[channel][device].Otype->get() == BX_ATA_DEVICE_CDROM) {
+        BX_DEBUG(( "CDROM on target %d/%d",channel,device));
+        BX_HD_THIS channels[channel].drives[device].device_type = IDE_CDROM;
+        BX_HD_THIS channels[channel].drives[device].cdrom.locked = 0;
+        BX_HD_THIS channels[channel].drives[device].sense.sense_key = SENSE_NONE;
+        BX_HD_THIS channels[channel].drives[device].sense.asc = 0;
+        BX_HD_THIS channels[channel].drives[device].sense.ascq = 0;
+       
+        // Check bit fields
+        BX_CONTROLLER(channel,device).sector_count = 0;
+        BX_CONTROLLER(channel,device).interrupt_reason.c_d = 1;
+        if (BX_CONTROLLER(channel,device).sector_count != 0x01)
+              BX_PANIC(("interrupt reason bit field error"));
+
+        BX_CONTROLLER(channel,device).sector_count = 0;
+        BX_CONTROLLER(channel,device).interrupt_reason.i_o = 1;
+        if (BX_CONTROLLER(channel,device).sector_count != 0x02)
+              BX_PANIC(("interrupt reason bit field error"));
+
+       BX_CONTROLLER(channel,device).sector_count = 0;
+       BX_CONTROLLER(channel,device).interrupt_reason.rel = 1;
+       if (BX_CONTROLLER(channel,device).sector_count != 0x04)
+             BX_PANIC(("interrupt reason bit field error"));
+
+       BX_CONTROLLER(channel,device).sector_count = 0;
+       BX_CONTROLLER(channel,device).interrupt_reason.tag = 3;
+       if (BX_CONTROLLER(channel,device).sector_count != 0x18)
+             BX_PANIC(("interrupt reason bit field error"));
+       BX_CONTROLLER(channel,device).sector_count = 0;
+
+       // allocate low level driver
+#ifdef LOWLEVEL_CDROM
+       BX_HD_THIS channels[channel].drives[device].cdrom.cd = new LOWLEVEL_CDROM(bx_options.atadevice[channel][device].Opath->getptr ());
+        BX_INFO(("CD on ata%d-%d: '%s'",channel, device, bx_options.atadevice[channel][device].Opath->getptr ()));
+
+       if (bx_options.atadevice[channel][device].Ostatus->get () == BX_INSERTED) {
+             if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom()) {
+                   BX_INFO(( "Media present in CD-ROM drive"));
+                   BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
+                   BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
+             } else {              
+                   BX_INFO(( "Could not locate CD-ROM, continuing with media not present"));
+                   BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+                   bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+             }
+       } else {
+#endif
+             BX_INFO(( "Media not present in CD-ROM drive" ));
+             BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+#ifdef LOWLEVEL_CDROM
+       }
+#endif
+      }
+    }
+  }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+      BX_HD_THIS pdc20230c.prog_mode = 0;
+      BX_HD_THIS pdc20230c.prog_count = 0;
+      BX_HD_THIS pdc20230c.p1f3_value = 0;
+      BX_HD_THIS pdc20230c.p1f4_value = 0;
+#endif
+
+
+  // generate CMOS values for hard drive if not using a CMOS image
+  if (!bx_options.cmos.OcmosImage->get ()) {
+    DEV_cmos_set_reg(0x12, 0x00); // start out with: no drive 0, no drive 1
+
+    if (BX_DRIVE_IS_HD(0,0)) {
+      // Flag drive type as Fh, use extended CMOS location as real type
+      DEV_cmos_set_reg(0x12, (DEV_cmos_get_reg(0x12) & 0x0f) | 0xf0);
+      DEV_cmos_set_reg(0x19, 47); // user definable type
+      // AMI BIOS: 1st hard disk #cyl low byte
+      DEV_cmos_set_reg(0x1b, (bx_options.atadevice[0][0].Ocylinders->get () & 0x00ff));
+      // AMI BIOS: 1st hard disk #cyl high byte
+      DEV_cmos_set_reg(0x1c, (bx_options.atadevice[0][0].Ocylinders->get () & 0xff00) >> 8);
+      // AMI BIOS: 1st hard disk #heads
+      DEV_cmos_set_reg(0x1d, (bx_options.atadevice[0][0].Oheads->get ()));
+      // AMI BIOS: 1st hard disk write precompensation cylinder, low byte
+      DEV_cmos_set_reg(0x1e, 0xff); // -1
+      // AMI BIOS: 1st hard disk write precompensation cylinder, high byte
+      DEV_cmos_set_reg(0x1f, 0xff); // -1
+      // AMI BIOS: 1st hard disk control byte
+      DEV_cmos_set_reg(0x20, (0xc0 | ((bx_options.atadevice[0][0].Oheads->get () > 8) << 3)));
+      // AMI BIOS: 1st hard disk landing zone, low byte
+      DEV_cmos_set_reg(0x21, DEV_cmos_get_reg(0x1b));
+      // AMI BIOS: 1st hard disk landing zone, high byte
+      DEV_cmos_set_reg(0x22, DEV_cmos_get_reg(0x1c));
+      // AMI BIOS: 1st hard disk sectors/track
+      DEV_cmos_set_reg(0x23, bx_options.atadevice[0][0].Ospt->get ());
+    }
+
+    //set up cmos for second hard drive
+    if (BX_DRIVE_IS_HD(0,1)) {
+      BX_DEBUG(("1: I will put 0xf into the second hard disk field"));
+      // fill in lower 4 bits of 0x12 for second HD
+      DEV_cmos_set_reg(0x12, (DEV_cmos_get_reg(0x12) & 0xf0) | 0x0f);
+      DEV_cmos_set_reg(0x1a, 47); // user definable type
+      // AMI BIOS: 2nd hard disk #cyl low byte
+      DEV_cmos_set_reg(0x24, (bx_options.atadevice[0][1].Ocylinders->get () & 0x00ff));
+      // AMI BIOS: 2nd hard disk #cyl high byte
+      DEV_cmos_set_reg(0x25, (bx_options.atadevice[0][1].Ocylinders->get () & 0xff00) >> 8);
+      // AMI BIOS: 2nd hard disk #heads
+      DEV_cmos_set_reg(0x26, (bx_options.atadevice[0][1].Oheads->get ()));
+      // AMI BIOS: 2nd hard disk write precompensation cylinder, low byte
+      DEV_cmos_set_reg(0x27, 0xff); // -1
+      // AMI BIOS: 2nd hard disk write precompensation cylinder, high byte
+      DEV_cmos_set_reg(0x28, 0xff); // -1
+      // AMI BIOS: 2nd hard disk, 0x80 if heads>8
+      DEV_cmos_set_reg(0x29, (bx_options.atadevice[0][1].Oheads->get () > 8) ? 0x80 : 0x00);
+      // AMI BIOS: 2nd hard disk landing zone, low byte
+      DEV_cmos_set_reg(0x2a, DEV_cmos_get_reg(0x24));
+      // AMI BIOS: 2nd hard disk landing zone, high byte
+      DEV_cmos_set_reg(0x2b, DEV_cmos_get_reg(0x25));
+      // AMI BIOS: 2nd hard disk sectors/track
+      DEV_cmos_set_reg(0x2c, bx_options.atadevice[0][1].Ospt->get ());
+    }
+
+    DEV_cmos_set_reg(0x39, 0);
+    DEV_cmos_set_reg(0x3a, 0);
+    for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+      for (Bit8u device=0; device<2; device ++) {
+        if (bx_options.atadevice[channel][device].Opresent->get()) {
+          if (BX_DRIVE_IS_HD(channel,device)) {
+            Bit16u cylinders = bx_options.atadevice[channel][device].Ocylinders->get();
+            Bit16u heads = bx_options.atadevice[channel][device].Oheads->get();
+            Bit16u spt = bx_options.atadevice[channel][device].Ospt->get();
+            Bit8u  translation = bx_options.atadevice[channel][device].Otranslation->get();
+
+            Bit8u reg = 0x39 + channel/2;
+            Bit8u bitshift = 2 * (device+(2 * (channel%2)));
+     
+            // Find the right translation if autodetect
+            if (translation == BX_ATA_TRANSLATION_AUTO) {
+              if((cylinders <= 1024) && (heads <= 16) && (spt <= 63)) {
+                translation = BX_ATA_TRANSLATION_NONE;
+                } 
+              else if (((Bit32u)cylinders * (Bit32u)heads) <= 131072) {
+                translation = BX_ATA_TRANSLATION_LARGE;
+                } 
+              else translation = BX_ATA_TRANSLATION_LBA;
+
+              BX_INFO(("translation on ata%d-%d set to '%s'",channel, device, 
+                        translation==BX_ATA_TRANSLATION_NONE?"none":
+                        translation==BX_ATA_TRANSLATION_LARGE?"large":
+                        "lba"));
+              }
+
+            // FIXME we should test and warn 
+            // - if LBA and spt != 63
+            // - if RECHS and heads != 16
+            // - if NONE and size > 1024*16*SPT blocks
+            // - if LARGE and size > 8192*16*SPT blocks
+            // - if RECHS and size > 1024*240*SPT blocks
+            // - if LBA and size > 1024*255*63, not that we can do much about it
+
+            switch(translation) {
+              case BX_ATA_TRANSLATION_NONE:
+                DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (0 << bitshift));
+                break;
+              case BX_ATA_TRANSLATION_LBA:
+                DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (1 << bitshift));
+                break;
+              case BX_ATA_TRANSLATION_LARGE:
+                DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (2 << bitshift));
+                break;
+              case BX_ATA_TRANSLATION_RECHS:
+                DEV_cmos_set_reg(reg, DEV_cmos_get_reg(reg) | (3 << bitshift));
+                break;
+              }
+            }
+          }
+        }
+      }
+
+    // Set the "non-extended" boot device. This will default to DISKC if cdrom
+    if ( bx_options.Obootdrive->get () != BX_BOOT_FLOPPYA) {
+      // system boot sequence C:, A:
+      DEV_cmos_set_reg(0x2d, DEV_cmos_get_reg(0x2d) & 0xdf);
+      }
+    else { // 'a'
+      // system boot sequence A:, C:
+      DEV_cmos_set_reg(0x2d, DEV_cmos_get_reg(0x2d) | 0x20);
+      }
+
+    // Set the "extended" boot device, byte 0x3D (needed for cdrom booting)
+    if ( bx_options.Obootdrive->get () == BX_BOOT_FLOPPYA) {
+      // system boot sequence A:
+      DEV_cmos_set_reg(0x3d, 0x01);
+      BX_INFO(("Boot device will be 'a'"));
+      }
+    else if ( bx_options.Obootdrive->get () == BX_BOOT_DISKC) { 
+      // system boot sequence C:
+      DEV_cmos_set_reg(0x3d, 0x02);
+      BX_INFO(("Boot device will be 'c'"));
+      }
+    else if ( bx_options.Obootdrive->get () == BX_BOOT_CDROM) { 
+      // system boot sequence cdrom
+      DEV_cmos_set_reg(0x3d, 0x03);
+      BX_INFO(("Boot device will be 'cdrom'"));
+      }
+      
+    // Set the signature check flag in cmos, inverted for compatibility
+    DEV_cmos_set_reg(0x38, bx_options.OfloppySigCheck->get());
+    BX_INFO(("Floppy boot signature check is %sabled", bx_options.OfloppySigCheck->get() ? "dis" : "en"));
+    }
+
+}
+
+  void
+bx_hard_drive_c::reset(unsigned type)
+{
+  for (unsigned channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if (BX_HD_THIS channels[channel].irq)
+      DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+  }
+}
+
+
+#define GOTO_RETURN_VALUE  if(io_len==4){\
+                             goto return_value32;\
+                             }\
+                           else if(io_len==2){\
+                             value16=(Bit16u)value32;\
+                             goto return_value16;\
+                             }\
+                           else{\
+                             value8=(Bit8u)value32;\
+                             goto return_value8;\
+                             }
+                           
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_hard_drive_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_HD_SMF
+  bx_hard_drive_c *class_ptr = (bx_hard_drive_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_hard_drive_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_HD_SMF
+  Bit8u value8;
+  Bit16u value16;
+  Bit32u value32;
+
+  Bit8u  channel = BX_MAX_ATA_CHANNEL;
+  Bit32u port = 0xff; // undefined
+
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr1) {
+      port = address - BX_HD_THIS channels[channel].ioaddr1;
+      break;
+      }
+    else if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr2) {
+      port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10;
+      break;
+      }
+    }
+
+  if (channel == BX_MAX_ATA_CHANNEL) {
+    if ((address < 0x03f6) || (address > 0x03f7)) {
+      BX_PANIC(("read: unable to find ATA channel, ioport=0x%04x", address));
+    } else {
+      channel = 0;
+      port = address - 0x03e0;
+    }
+  }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20230c is only available for first ata channel
+if (channel == 0) {
+
+  // Detect the switch to programming mode
+  if (!BX_HD_THIS pdc20230c.prog_mode) {
+    switch (port) {
+      case 0x02:
+        if ((BX_HD_THIS pdc20230c.prog_count == 0) || (BX_HD_THIS pdc20230c.prog_count > 2)) {
+          BX_HD_THIS pdc20230c.prog_count++;
+        }
+       else {
+          BX_HD_THIS pdc20230c.prog_count=0;
+       }
+       break;
+      case 0x16:
+        if ((BX_HD_THIS pdc20230c.prog_count == 1) || (BX_HD_THIS pdc20230c.prog_count == 2)) {
+         BX_HD_THIS pdc20230c.prog_count++;
+       }
+       else {
+          BX_HD_THIS pdc20230c.prog_count=0;
+       }
+       break;
+      default:
+       BX_HD_THIS pdc20230c.prog_count=0;
+    }
+
+    if (BX_HD_THIS pdc20230c.prog_count == 5) {
+      BX_HD_THIS pdc20230c.prog_mode = 1;
+      BX_SELECTED_CONTROLLER(channel).sector_count &= 0x7f;
+      BX_INFO(("Promise VLB-IDE DC2300: Switching to Programming mode"));
+    }
+  }
+
+  // Returns value when in programming mode
+  if (BX_HD_THIS pdc20230c.prog_mode) {
+    switch (port) {
+      case 0x05:
+       // Leave programming mode
+        BX_HD_THIS pdc20230c.prog_mode = 0;
+        BX_INFO(("Promise VLB-IDE DC2300: Leaving Programming mode"));
+       // Value will be sent be normal code
+        break;
+      case 0x03:
+       // Special programming register
+        value32 = BX_HD_THIS pdc20230c.p1f3_value;
+        GOTO_RETURN_VALUE ;
+        break;
+      case 0x04:
+       // Special programming register
+        value32 = BX_HD_THIS pdc20230c.p1f4_value;
+        GOTO_RETURN_VALUE ;
+        break;
+    }
+  }
+}
+#endif
+
+  switch (port) {
+    case 0x00: // hard disk data (16bit) 0x1f0
+      if (BX_SELECTED_CONTROLLER(channel).status.drq == 0) {
+           BX_ERROR(("IO read(0x%04x) with drq == 0: last command was %02xh",
+                    address, (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+            return(0);
+      }
+      BX_DEBUG(("IO read(0x%04x): current command is %02xh",
+            address, (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+      switch (BX_SELECTED_CONTROLLER(channel).current_command) {
+        case 0x20: // READ SECTORS, with retries
+        case 0x21: // READ SECTORS, without retries
+          if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512)
+            BX_PANIC(("IO read(0x%04x): buffer_index >= 512", address));
+
+#if BX_SupportRepeatSpeedups
+          if (DEV_bulk_io_quantum_requested()) {
+            unsigned transferLen, quantumsMax;
+
+            quantumsMax =
+              (512 - BX_SELECTED_CONTROLLER(channel).buffer_index) / io_len;
+            if ( quantumsMax == 0)
+              BX_PANIC(("IO read(0x%04x): not enough space for read", address));
+            DEV_bulk_io_quantum_transferred() =
+                DEV_bulk_io_quantum_requested();
+            if (quantumsMax < DEV_bulk_io_quantum_transferred())
+              DEV_bulk_io_quantum_transferred() = quantumsMax;
+            transferLen = io_len * DEV_bulk_io_quantum_transferred();
+            memcpy((Bit8u*) DEV_bulk_io_host_addr(),
+              &BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index], 
+              transferLen);
+            DEV_bulk_io_host_addr() += transferLen;
+            BX_SELECTED_CONTROLLER(channel).buffer_index += transferLen;
+            value32 = 0; // Value returned not important;
+            }
+          else
+#endif
+            {
+            value32 = 0L;
+            switch(io_len){
+              case 4:
+                value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] << 24);
+                value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] << 16);
+              case 2:
+                value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] << 8);
+                value32 |=  BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index];
+              }
+            BX_SELECTED_CONTROLLER(channel).buffer_index += io_len;
+            }
+
+          // if buffer completely read
+          if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+            // update sector count, sector number, cylinder,
+            // drive, head, status
+            // if there are more sectors, read next one in...
+            //
+            BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+
+           increment_address(channel);
+
+            BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+            if (bx_options.OnewHardDriveSupport->get ())
+              BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+            else
+              BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+            BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+            if (BX_SELECTED_CONTROLLER(channel).sector_count==0) {
+              BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+              }
+            else { /* read next one into controller buffer */
+              off_t logical_sector;
+              off_t ret;
+
+              BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+              BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+
+#if TEST_READ_BEYOND_END==1
+             BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+             if (!calculate_logical_address(channel, &logical_sector)) {
+               BX_ERROR(("multi-sector read reached invalid sector %lu, aborting", (unsigned long)logical_sector));
+               command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+               GOTO_RETURN_VALUE ;
+             }
+             ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+              if (ret < 0) {
+                BX_ERROR(("could not lseek() hard drive image file"));
+               command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+               GOTO_RETURN_VALUE ;
+             }
+             ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+              if (ret < 512) {
+                BX_ERROR(("logical sector was %lu", (unsigned long)logical_sector));
+                BX_ERROR(("could not read() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+               command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+               GOTO_RETURN_VALUE ;
+             }
+
+              BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+             raise_interrupt(channel);
+           }
+         }
+         GOTO_RETURN_VALUE ;
+          break;
+
+        case 0xec:    // IDENTIFY DEVICE
+       case 0xa1:
+          if (bx_options.OnewHardDriveSupport->get ()) {
+            unsigned index;
+
+            BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+            BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+            BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+            index = BX_SELECTED_CONTROLLER(channel).buffer_index;
+            value32 = BX_SELECTED_CONTROLLER(channel).buffer[index];
+            index++;
+            if (io_len >= 2) {
+              value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 8);
+              index++;
+              }
+            if (io_len == 4) {
+              value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index] << 16);
+              value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+1] << 24);
+              index += 2;
+              }
+            BX_SELECTED_CONTROLLER(channel).buffer_index = index;
+
+            if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+              BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+             if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+                   BX_INFO(("Read all drive ID Bytes ..."));
+              }
+            GOTO_RETURN_VALUE;
+         }
+          else
+            BX_PANIC(("IO read(0x%04x): current command is %02xh", address,
+              (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+
+           case 0xa0: {
+                 unsigned index = BX_SELECTED_CONTROLLER(channel).buffer_index;
+                 unsigned increment = 0;
+
+                 // Load block if necessary
+                 if (index >= 2048) {
+                       if (index > 2048)
+                             BX_PANIC(("index > 2048 : 0x%x",index));
+                       switch (BX_SELECTED_DRIVE(channel).atapi.command) {
+                             case 0x28: // read (10)
+                             case 0xa8: // read (12)
+#ifdef LOWLEVEL_CDROM
+                                   if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                     BX_PANIC(("Read with CDROM not ready"));
+                                   } 
+                                   BX_SELECTED_DRIVE(channel).cdrom.cd->read_block(BX_SELECTED_CONTROLLER(channel).buffer,
+                                                                       BX_SELECTED_DRIVE(channel).cdrom.next_lba);
+                                   BX_SELECTED_DRIVE(channel).cdrom.next_lba++;
+                                   BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks--;
+
+                                   if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+                                         if (!BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks)
+                                               BX_INFO(("Last READ block loaded {CDROM}"));
+                                         else
+                                               BX_INFO(("READ block loaded (%d remaining) {CDROM}",
+                                                         BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks));
+
+                                   // one block transfered, start at beginning
+                                   index = 0;
+#else
+                                   BX_PANIC(("Read with no LOWLEVEL_CDROM"));
+#endif
+                                   break;
+
+                             default: // no need to load a new block
+                                   break;
+                       }
+                 }
+
+                 value32 = BX_SELECTED_CONTROLLER(channel).buffer[index+increment];
+                 increment++;
+                 if (io_len >= 2) {
+                       value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 8);
+                       increment++;
+                 }
+                 if (io_len == 4) {
+                       value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment] << 16);
+                       value32 |= (BX_SELECTED_CONTROLLER(channel).buffer[index+increment+1] << 24);
+                       increment += 2;
+                 }
+                 BX_SELECTED_CONTROLLER(channel).buffer_index = index + increment;
+                 BX_SELECTED_CONTROLLER(channel).drq_index += increment;
+
+                 if (BX_SELECTED_CONTROLLER(channel).drq_index >= (unsigned)BX_SELECTED_DRIVE(channel).atapi.drq_bytes) {
+                       BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+                       BX_SELECTED_CONTROLLER(channel).drq_index = 0;
+
+                       BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining -= BX_SELECTED_DRIVE(channel).atapi.drq_bytes;
+
+                       if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining > 0) {
+                             // one or more blocks remaining (works only for single block commands)
+                             if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+                                   BX_INFO(("PACKET drq bytes read"));
+                             BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+                             BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+                             BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+                             BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0;
+
+                             // set new byte count if last block
+                             if (BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining < BX_SELECTED_CONTROLLER(channel).byte_count) {
+                                   BX_SELECTED_CONTROLLER(channel).byte_count = BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining;
+                             }
+                             BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count;
+
+                             raise_interrupt(channel);
+                       } else {
+                             // all bytes read
+                             if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+                                   BX_INFO(("PACKET all bytes read"));
+                             BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+                             BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+                             BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+                             BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+                             BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+                             BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+                             BX_SELECTED_CONTROLLER(channel).status.err = 0;
+                             
+                             raise_interrupt(channel);
+                       }
+                 }
+                  GOTO_RETURN_VALUE;
+                 break;
+           }
+
+       // List all the read operations that are defined in the ATA/ATAPI spec
+       // that we don't support.  Commands that are listed here will cause a
+       // BX_ERROR, which is non-fatal, and the command will be aborted.
+       case 0x08: BX_ERROR(("read cmd 0x08 (DEVICE RESET) not supported")); command_aborted(channel, 0x08); break;
+       case 0x10: BX_ERROR(("read cmd 0x10 (RECALIBRATE) not supported")); command_aborted(channel, 0x10); break;
+       case 0x22: BX_ERROR(("read cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break;
+       case 0x23: BX_ERROR(("read cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break;
+       case 0x24: BX_ERROR(("read cmd 0x24 (READ SECTORS EXT) not supported")); command_aborted(channel, 0x24); break;
+       case 0x25: BX_ERROR(("read cmd 0x25 (READ DMA EXT) not supported")); command_aborted(channel, 0x25); break;
+       case 0x26: BX_ERROR(("read cmd 0x26 (READ DMA QUEUED EXT) not supported")); command_aborted(channel, 0x26); break;
+       case 0x27: BX_ERROR(("read cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x27); break;
+       case 0x29: BX_ERROR(("read cmd 0x29 (READ MULTIPLE EXT) not supported")); command_aborted(channel, 0x29); break;
+       case 0x2A: BX_ERROR(("read cmd 0x2A (READ STREAM DMA) not supported")); command_aborted(channel, 0x2A); break;
+       case 0x2B: BX_ERROR(("read cmd 0x2B (READ STREAM PIO) not supported")); command_aborted(channel, 0x2B); break;
+       case 0x2F: BX_ERROR(("read cmd 0x2F (READ LOG EXT) not supported")); command_aborted(channel, 0x2F); break;
+       case 0x30: BX_ERROR(("read cmd 0x30 (WRITE SECTORS) not supported")); command_aborted(channel, 0x30); break;
+       case 0x31: BX_ERROR(("read cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break;
+       case 0x32: BX_ERROR(("read cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break;
+       case 0x33: BX_ERROR(("read cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break;
+       case 0x34: BX_ERROR(("read cmd 0x34 (WRITE SECTORS EXT) not supported")); command_aborted(channel, 0x34); break;
+       case 0x35: BX_ERROR(("read cmd 0x35 (WRITE DMA EXT) not supported")); command_aborted(channel, 0x35); break;
+       case 0x36: BX_ERROR(("read cmd 0x36 (WRITE DMA QUEUED EXT) not supported")); command_aborted(channel, 0x36); break;
+       case 0x37: BX_ERROR(("read cmd 0x37 (SET MAX ADDRESS EXT) not supported")); command_aborted(channel, 0x37); break;
+       case 0x38: BX_ERROR(("read cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported")); command_aborted(channel, 0x38); break;
+       case 0x39: BX_ERROR(("read cmd 0x39 (WRITE MULTIPLE EXT) not supported")); command_aborted(channel, 0x39); break;
+       case 0x3A: BX_ERROR(("read cmd 0x3A (WRITE STREAM DMA) not supported")); command_aborted(channel, 0x3A); break;
+       case 0x3B: BX_ERROR(("read cmd 0x3B (WRITE STREAM PIO) not supported")); command_aborted(channel, 0x3B); break;
+       case 0x3F: BX_ERROR(("read cmd 0x3F (WRITE LOG EXT) not supported")); command_aborted(channel, 0x3F); break;
+       case 0x40: BX_ERROR(("read cmd 0x40 (READ VERIFY SECTORS) not supported")); command_aborted(channel, 0x40); break;
+       case 0x41: BX_ERROR(("read cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break;
+       case 0x42: BX_ERROR(("read cmd 0x42 (READ VERIFY SECTORS EXT) not supported")); command_aborted(channel, 0x42); break;
+       case 0x50: BX_ERROR(("read cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break;
+       case 0x51: BX_ERROR(("read cmd 0x51 (CONFIGURE STREAM) not supported")); command_aborted(channel, 0x51); break;
+       case 0x70: BX_ERROR(("read cmd 0x70 (SEEK) not supported")); command_aborted(channel, 0x70); break;
+       case 0x87: BX_ERROR(("read cmd 0x87 (CFA TRANSLATE SECTOR) not supported")); command_aborted(channel, 0x87); break;
+       case 0x90: BX_ERROR(("read cmd 0x90 (EXECUTE DEVICE DIAGNOSTIC) not supported")); command_aborted(channel, 0x90); break;
+       case 0x91: BX_ERROR(("read cmd 0x91 (INITIALIZE DEVICE PARAMETERS) not supported")); command_aborted(channel, 0x91); break;
+       case 0x92: BX_ERROR(("read cmd 0x92 (DOWNLOAD MICROCODE) not supported")); command_aborted(channel, 0x92); break;
+       case 0x94: BX_ERROR(("read cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break;
+       case 0x95: BX_ERROR(("read cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break;
+       case 0x96: BX_ERROR(("read cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break;
+       case 0x97: BX_ERROR(("read cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break;
+       case 0x98: BX_ERROR(("read cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break;
+       case 0x99: BX_ERROR(("read cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break;
+       case 0xA2: BX_ERROR(("read cmd 0xA2 (SERVICE) not supported")); command_aborted(channel, 0xA2); break;
+       case 0xB0: BX_ERROR(("read cmd 0xB0 (SMART DISABLE OPERATIONS) not supported")); command_aborted(channel, 0xB0); break;
+       case 0xB1: BX_ERROR(("read cmd 0xB1 (DEVICE CONFIGURATION FREEZE LOCK) not supported")); command_aborted(channel, 0xB1); break;
+       case 0xC0: BX_ERROR(("read cmd 0xC0 (CFA ERASE SECTORS) not supported")); command_aborted(channel, 0xC0); break;
+       case 0xC4: BX_ERROR(("read cmd 0xC4 (READ MULTIPLE) not supported")); command_aborted(channel, 0xC4); break;
+       case 0xC5: BX_ERROR(("read cmd 0xC5 (WRITE MULTIPLE) not supported")); command_aborted(channel, 0xC5); break;
+       case 0xC6: BX_ERROR(("read cmd 0xC6 (SET MULTIPLE MODE) not supported")); command_aborted(channel, 0xC6); break;
+       case 0xC7: BX_ERROR(("read cmd 0xC7 (READ DMA QUEUED) not supported")); command_aborted(channel, 0xC7); break;
+       case 0xC8: BX_ERROR(("read cmd 0xC8 (READ DMA) not supported")); command_aborted(channel, 0xC8); break;
+       case 0xC9: BX_ERROR(("read cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break;
+       case 0xCA: BX_ERROR(("read cmd 0xCA (WRITE DMA) not supported")); command_aborted(channel, 0xCA); break;
+       case 0xCC: BX_ERROR(("read cmd 0xCC (WRITE DMA QUEUED) not supported")); command_aborted(channel, 0xCC); break;
+       case 0xCD: BX_ERROR(("read cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported")); command_aborted(channel, 0xCD); break;
+       case 0xD1: BX_ERROR(("read cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported")); command_aborted(channel, 0xD1); break;
+       case 0xDA: BX_ERROR(("read cmd 0xDA (GET MEDIA STATUS) not supported")); command_aborted(channel, 0xDA); break;
+       case 0xDE: BX_ERROR(("read cmd 0xDE (MEDIA LOCK) not supported")); command_aborted(channel, 0xDE); break;
+       case 0xDF: BX_ERROR(("read cmd 0xDF (MEDIA UNLOCK) not supported")); command_aborted(channel, 0xDF); break;
+       case 0xE0: BX_ERROR(("read cmd 0xE0 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0xE0); break;
+       case 0xE1: BX_ERROR(("read cmd 0xE1 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0xE1); break;
+       case 0xE2: BX_ERROR(("read cmd 0xE2 (STANDBY) not supported")); command_aborted(channel, 0xE2); break;
+       case 0xE3: BX_ERROR(("read cmd 0xE3 (IDLE) not supported")); command_aborted(channel, 0xE3); break;
+       case 0xE4: BX_ERROR(("read cmd 0xE4 (READ BUFFER) not supported")); command_aborted(channel, 0xE4); break;
+       case 0xE5: BX_ERROR(("read cmd 0xE5 (CHECK POWER MODE) not supported")); command_aborted(channel, 0xE5); break;
+       case 0xE6: BX_ERROR(("read cmd 0xE6 (SLEEP) not supported")); command_aborted(channel, 0xE6); break;
+       case 0xE7: BX_ERROR(("read cmd 0xE7 (FLUSH CACHE) not supported")); command_aborted(channel, 0xE7); break;
+       case 0xE8: BX_ERROR(("read cmd 0xE8 (WRITE BUFFER) not supported")); command_aborted(channel, 0xE8); break;
+       case 0xEA: BX_ERROR(("read cmd 0xEA (FLUSH CACHE EXT) not supported")); command_aborted(channel, 0xEA); break;
+       case 0xED: BX_ERROR(("read cmd 0xED (MEDIA EJECT) not supported")); command_aborted(channel, 0xED); break;
+       case 0xEF: BX_ERROR(("read cmd 0xEF (SET FEATURES) not supported")); command_aborted(channel, 0xEF); break;
+       case 0xF1: BX_ERROR(("read cmd 0xF1 (SECURITY SET PASSWORD) not supported")); command_aborted(channel, 0xF1); break;
+       case 0xF2: BX_ERROR(("read cmd 0xF2 (SECURITY UNLOCK) not supported")); command_aborted(channel, 0xF2); break;
+       case 0xF3: BX_ERROR(("read cmd 0xF3 (SECURITY ERASE PREPARE) not supported")); command_aborted(channel, 0xF3); break;
+       case 0xF4: BX_ERROR(("read cmd 0xF4 (SECURITY ERASE UNIT) not supported")); command_aborted(channel, 0xF4); break;
+       case 0xF5: BX_ERROR(("read cmd 0xF5 (SECURITY FREEZE LOCK) not supported")); command_aborted(channel, 0xF5); break;
+       case 0xF6: BX_ERROR(("read cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported")); command_aborted(channel, 0xF6); break;
+       case 0xF8: BX_ERROR(("read cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported")); command_aborted(channel, 0xF8); break;
+       case 0xF9: BX_ERROR(("read cmd 0xF9 (SET MAX ADDRESS) not supported")); command_aborted(channel, 0xF9); break;
+
+        default:
+          BX_PANIC(("IO read(0x%04x): current command is %02xh", address,
+            (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+        }
+      break;
+
+    case 0x01: // hard disk error register 0x1f1
+      BX_SELECTED_CONTROLLER(channel).status.err = 0;
+      value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).error_register;
+      goto return_value8;
+      break;
+    case 0x02: // hard disk sector count / interrupt reason 0x1f2
+      value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_count;
+      goto return_value8;
+      break;
+    case 0x03: // sector number 0x1f3
+      value8 = (!BX_SELECTED_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).sector_no;
+      goto return_value8;
+    case 0x04: // cylinder low 0x1f4  
+               // -- WARNING : On real hardware the controller registers are shared between drives. 
+               // So we must respond even if the select device is not present. Some OS uses this fact 
+               // to detect the disks.... minix2 for example
+      value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : (BX_SELECTED_CONTROLLER(channel).cylinder_no & 0x00ff);
+      goto return_value8;
+    case 0x05: // cylinder high 0x1f5
+               // -- WARNING : On real hardware the controller registers are shared between drives. 
+               // So we must respond even if the select device is not present. Some OS uses this fact 
+               // to detect the disks.... minix2 for example
+      value8 = (!BX_ANY_IS_PRESENT(channel)) ? 0 : BX_SELECTED_CONTROLLER(channel).cylinder_no >> 8;
+      goto return_value8;
+
+    case 0x06: // hard disk drive and head register 0x1f6
+      // b7 Extended data field for ECC
+      // b6/b5: Used to be sector size.  00=256,01=512,10=1024,11=128
+      //   Since 512 was always used, bit 6 was taken to mean LBA mode:
+      //     b6 1=LBA mode, 0=CHS mode
+      //     b5 1
+      // b4: DRV
+      // b3..0 HD3..HD0
+      value8 = (1 << 7) |
+               ((BX_SELECTED_CONTROLLER(channel).lba_mode>0) << 6) |
+               (1 << 5) | // 01b = 512 sector size
+               (BX_HD_THIS channels[channel].drive_select << 4) |
+               (BX_SELECTED_CONTROLLER(channel).head_no << 0);
+      goto return_value8;
+      break;
+//BX_CONTROLLER(channel,0).lba_mode
+
+    case 0x07: // Hard Disk Status 0x1f7
+    case 0x16: // Hard Disk Alternate Status 0x3f6
+      if (!BX_ANY_IS_PRESENT(channel)) {
+           // (mch) Just return zero for these registers
+           value8 = 0;
+      } else {
+      value8 = (
+        (BX_SELECTED_CONTROLLER(channel).status.busy << 7) |
+        (BX_SELECTED_CONTROLLER(channel).status.drive_ready << 6) |
+        (BX_SELECTED_CONTROLLER(channel).status.write_fault << 5) |
+        (BX_SELECTED_CONTROLLER(channel).status.seek_complete << 4) |
+        (BX_SELECTED_CONTROLLER(channel).status.drq << 3) |
+        (BX_SELECTED_CONTROLLER(channel).status.corrected_data << 2) |
+        (BX_SELECTED_CONTROLLER(channel).status.index_pulse << 1) |
+        (BX_SELECTED_CONTROLLER(channel).status.err) );
+      BX_SELECTED_CONTROLLER(channel).status.index_pulse_count++;
+      BX_SELECTED_CONTROLLER(channel).status.index_pulse = 0;
+      if (BX_SELECTED_CONTROLLER(channel).status.index_pulse_count >= INDEX_PULSE_CYCLE) {
+        BX_SELECTED_CONTROLLER(channel).status.index_pulse = 1;
+        BX_SELECTED_CONTROLLER(channel).status.index_pulse_count = 0;
+        }
+      }
+      if (port == 0x07) {
+        DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+        }
+      goto return_value8;
+      break;
+
+    case 0x17: // Hard Disk Address Register 0x3f7
+      // Obsolete and unsupported register.  Not driven by hard
+      // disk controller.  Report all 1's.  If floppy controller
+      // is handling this address, it will call this function
+      // set/clear D7 (the only bit it handles), then return
+      // the combined value
+      value8 = 0xff;
+      goto return_value8;
+      break;
+
+    default:
+      BX_PANIC(("hard drive: io read to address %x unsupported",
+        (unsigned) address));
+    }
+
+  BX_PANIC(("hard drive: shouldnt get here!"));
+  return(0);
+
+  return_value32:
+  BX_DEBUG(("32-bit read from %04x = %08x {%s}",
+           (unsigned) address, value32, BX_SELECTED_TYPE_STRING(channel)));
+  return value32;
+
+  return_value16:
+  BX_DEBUG(("16-bit read from %04x = %04x {%s}",
+           (unsigned) address, value16, BX_SELECTED_TYPE_STRING(channel)));
+  return value16;
+
+  return_value8:
+  BX_DEBUG(("8-bit read from %04x = %02x {%s}",
+           (unsigned) address, value8, BX_SELECTED_TYPE_STRING(channel)));
+  return value8;
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_hard_drive_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_HD_SMF
+  bx_hard_drive_c *class_ptr = (bx_hard_drive_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_hard_drive_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_HD_SMF
+  off_t logical_sector;
+  off_t ret;
+  bx_bool prev_control_reset;
+
+  Bit8u  channel = BX_MAX_ATA_CHANNEL;
+  Bit32u port = 0xff; // undefined
+
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr1) {
+      port = address - BX_HD_THIS channels[channel].ioaddr1;
+      break;
+      }
+    else if ((address & 0xfff8) == BX_HD_THIS channels[channel].ioaddr2) {
+      port = address - BX_HD_THIS channels[channel].ioaddr2 + 0x10;
+      break;
+      }
+    }
+
+  if (channel == BX_MAX_ATA_CHANNEL) {
+    if (address != 0x03f6) {
+      BX_PANIC(("write: unable to find ATA channel, ioport=0x%04x", address));
+    } else {
+      channel = 0;
+      port = address - 0x03e0;
+    }
+  }
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20230c is only available for first ata channel
+if (channel == 0) {
+  BX_HD_THIS pdc20230c.prog_count = 0;
+
+  if (BX_HD_THIS pdc20230c.prog_mode != 0) {
+    switch (port) {
+      case 0x03:
+       BX_HD_THIS pdc20230c.p1f3_value = value;
+       return;
+        break;
+      case 0x04:
+       BX_HD_THIS pdc20230c.p1f4_value = value;
+       return;
+        break;
+    }
+  }
+}
+#endif
+
+  if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) {
+       switch (io_len) {
+             case 1:
+                   BX_INFO(("8-bit write to %04x = %02x {%s}",
+                             (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+                   break;
+                   
+             case 2:
+                   BX_INFO(("16-bit write to %04x = %04x {%s}",
+                             (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+                   break;
+
+             case 4:
+                   BX_INFO(("32-bit write to %04x = %08x {%s}",
+                             (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+                   break;
+
+             default:
+                   BX_INFO(("unknown-size write to %04x = %08x {%s}",
+                             (unsigned) address, (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+                   break;
+       }
+  }
+
+  BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value));
+
+  switch (port) {
+    case 0x00: // 0x1f0
+      switch (BX_SELECTED_CONTROLLER(channel).current_command) {
+        case 0x30: // WRITE SECTORS
+          if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512)
+            BX_PANIC(("IO write(0x%04x): buffer_index >= 512", address));
+
+#if BX_SupportRepeatSpeedups
+          if (DEV_bulk_io_quantum_requested()) {
+            unsigned transferLen, quantumsMax;
+
+            quantumsMax =
+              (512 - BX_SELECTED_CONTROLLER(channel).buffer_index) / io_len;
+            if ( quantumsMax == 0)
+              BX_PANIC(("IO write(0x%04x): not enough space for write", address));
+            DEV_bulk_io_quantum_transferred() =
+                DEV_bulk_io_quantum_requested();
+            if (quantumsMax < DEV_bulk_io_quantum_transferred())
+              DEV_bulk_io_quantum_transferred() = quantumsMax;
+            transferLen = io_len * DEV_bulk_io_quantum_transferred();
+            memcpy(
+              &BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index], 
+              (Bit8u*) DEV_bulk_io_host_addr(),
+              transferLen);
+           DEV_bulk_io_host_addr() += transferLen;
+            BX_SELECTED_CONTROLLER(channel).buffer_index += transferLen;
+            }
+          else
+#endif
+            {
+            switch(io_len){
+              case 4:
+                BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+3] = (Bit8u)(value >> 24);
+                BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+2] = (Bit8u)(value >> 16);
+              case 2:
+                BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (Bit8u)(value >> 8);
+                BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index]   = (Bit8u) value;
+              }
+            BX_SELECTED_CONTROLLER(channel).buffer_index += io_len;
+            }
+
+          /* if buffer completely writtten */
+          if (BX_SELECTED_CONTROLLER(channel).buffer_index >= 512) {
+            off_t logical_sector;
+            off_t ret;
+
+#if TEST_WRITE_BEYOND_END==1
+           BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+           if (!calculate_logical_address(channel, &logical_sector)) {
+             BX_ERROR(("write reached invalid sector %lu, aborting", (unsigned long)logical_sector));
+             command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+             return;
+            }
+#if TEST_WRITE_BEYOND_END==2
+           logical_sector += 100000;
+#endif
+           ret = BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+            if (ret < 0) {
+              BX_ERROR(("could not lseek() hard drive image file at byte %lu", (unsigned long)logical_sector * 512));
+             command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+             return;
+           }
+           ret = BX_SELECTED_DRIVE(channel).hard_drive->write((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+            if (ret < 512) {
+              BX_ERROR(("could not write() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+             command_aborted (channel, BX_SELECTED_CONTROLLER(channel).current_command);
+             return;
+           }
+
+            BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+
+            /* update sector count, sector number, cylinder,
+             * drive, head, status
+             * if there are more sectors, read next one in...
+             */
+
+           increment_address(channel);
+
+            /* When the write is complete, controller clears the DRQ bit and
+             * sets the BSY bit.
+             * If at least one more sector is to be written, controller sets DRQ bit,
+             * clears BSY bit, and issues IRQ 
+             */
+
+            if (BX_SELECTED_CONTROLLER(channel).sector_count!=0) {
+              BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+              BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+              BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+              BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+              BX_SELECTED_CONTROLLER(channel).status.err = 0;
+              }
+            else { /* no more sectors to write */
+              BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+              BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+              BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+              BX_SELECTED_CONTROLLER(channel).status.err = 0;
+              BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+              }
+           raise_interrupt(channel);
+            }
+          break;
+
+           case 0xa0: // PACKET
+                 if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE)
+                       BX_PANIC(("IO write(0x%04x): buffer_index >= PACKET_SIZE", address));
+                 BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index] = value;
+                 BX_SELECTED_CONTROLLER(channel).buffer[BX_SELECTED_CONTROLLER(channel).buffer_index+1] = (value >> 8);
+                 BX_SELECTED_CONTROLLER(channel).buffer_index += 2;
+
+                 /* if packet completely writtten */
+                 if (BX_SELECTED_CONTROLLER(channel).buffer_index >= PACKET_SIZE) {
+                       // complete command received
+                       Bit8u atapi_command = BX_SELECTED_CONTROLLER(channel).buffer[0];
+
+                       if (bx_dbg.cdrom)
+                               BX_INFO(("cdrom: ATAPI command 0x%x started", atapi_command));
+
+                       switch (atapi_command) {
+                             case 0x00: // test unit ready
+                                   if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         atapi_cmd_nop(channel);
+                                   } else {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                   }
+                                   raise_interrupt(channel);
+                                   break;
+
+                             case 0x03: { // request sense
+                                   int alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4];
+                                   init_send_atapi_command(channel, atapi_command, 18, alloc_length);
+
+                                   // sense data
+                                   BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x70 | (1 << 7);
+                                   BX_SELECTED_CONTROLLER(channel).buffer[1] = 0;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[2] = BX_SELECTED_DRIVE(channel).sense.sense_key;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[3] = BX_SELECTED_DRIVE(channel).sense.information.arr[0];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[4] = BX_SELECTED_DRIVE(channel).sense.information.arr[1];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[5] = BX_SELECTED_DRIVE(channel).sense.information.arr[2];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[6] = BX_SELECTED_DRIVE(channel).sense.information.arr[3];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[7] = 17-7;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[8] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[0];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[9] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[1];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[10] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[2];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[11] = BX_SELECTED_DRIVE(channel).sense.specific_inf.arr[3];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[12] = BX_SELECTED_DRIVE(channel).sense.asc;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[13] = BX_SELECTED_DRIVE(channel).sense.ascq;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[14] = BX_SELECTED_DRIVE(channel).sense.fruc;
+                                   BX_SELECTED_CONTROLLER(channel).buffer[15] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[0];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[16] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[1];
+                                   BX_SELECTED_CONTROLLER(channel).buffer[17] = BX_SELECTED_DRIVE(channel).sense.key_spec.arr[2];
+
+                                   ready_to_send_atapi(channel);
+                             }
+                             break;
+                             
+                             case 0x1b: { // start stop unit
+                                   //bx_bool Immed = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 0) & 1;
+                                   bx_bool LoEj = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 1) & 1;
+                                   bx_bool Start = (BX_SELECTED_CONTROLLER(channel).buffer[4] >> 0) & 1;
+
+                                   if (!LoEj && !Start) { // stop the disc
+                                         BX_ERROR(("FIXME: Stop disc not implemented"));
+                                         atapi_cmd_nop(channel);
+                                         raise_interrupt(channel);
+                                   } else if (!LoEj && Start) { // start (spin up) the disc
+#ifdef LOWLEVEL_CDROM
+                                         BX_SELECTED_DRIVE(channel).cdrom.cd->start_cdrom();
+#endif
+                                         BX_ERROR(("FIXME: ATAPI start disc not reading TOC"));
+                                         atapi_cmd_nop(channel);
+                                         raise_interrupt(channel);
+                                   } else if (LoEj && !Start) { // Eject the disc
+                                          atapi_cmd_nop(channel);
+
+                                          if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+#ifdef LOWLEVEL_CDROM
+                                           BX_SELECTED_DRIVE(channel).cdrom.cd->eject_cdrom();
+#endif
+                                           BX_SELECTED_DRIVE(channel).cdrom.ready = 0;
+                                            bx_options.atadevice[channel][BX_SLAVE_SELECTED(channel)].Ostatus->set(BX_EJECTED);
+                                            bx_gui->update_drive_status_buttons();
+                                          }
+                                          raise_interrupt(channel);
+                                   } else { // Load the disc
+                                         // My guess is that this command only closes the tray, that's a no-op for us
+                                         atapi_cmd_nop(channel);
+                                         raise_interrupt(channel);
+                                   }
+                             }
+                             break;
+
+                             case 0xbd: { // mechanism status
+                                   uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 8);
+
+                                   if (alloc_length == 0)
+                                         BX_PANIC(("Zero allocation length to MECHANISM STATUS not impl."));
+
+                                   init_send_atapi_command(channel, atapi_command, 8, alloc_length);
+
+                                   BX_SELECTED_CONTROLLER(channel).buffer[0] = 0; // reserved for non changers
+                                   BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // reserved for non changers
+
+                                   BX_SELECTED_CONTROLLER(channel).buffer[2] = 0; // Current LBA (TODO!)
+                                   BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // Current LBA (TODO!)
+                                   BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // Current LBA (TODO!)
+
+                                   BX_SELECTED_CONTROLLER(channel).buffer[5] = 1; // one slot
+
+                                   BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // slot table length
+                                   BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // slot table length
+
+                                   ready_to_send_atapi(channel);
+                             }
+                             break;
+
+                             case 0x5a: { // mode sense
+                                   uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+
+                                   Bit8u PC = BX_SELECTED_CONTROLLER(channel).buffer[2] >> 6;
+                                   Bit8u PageCode = BX_SELECTED_CONTROLLER(channel).buffer[2] & 0x3f;
+
+                                   switch (PC) {
+                                         case 0x0: // current values
+                                               switch (PageCode) {
+                                                     case 0x01: // error recovery
+                                                           init_send_atapi_command(channel, atapi_command, sizeof(error_recovery_t) + 8, alloc_length);
+
+                                                           init_mode_sense_single(channel, &BX_SELECTED_DRIVE(channel).cdrom.current.error_recovery,
+                                                                                  sizeof(error_recovery_t));
+                                                           ready_to_send_atapi(channel);
+                                                           break;
+
+                                                     case 0x2a: // CD-ROM capabilities & mech. status
+                                                             init_send_atapi_command(channel, atapi_command, 28, alloc_length);
+                                                             init_mode_sense_single(channel, &BX_SELECTED_CONTROLLER(channel).buffer[8], 28);
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[8] = 0x2a;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[9] = 0x12;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[10] = 0x00;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[11] = 0x00;
+                                                             // Multisession, Mode 2 Form 2, Mode 2 Form 1
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[12] = 0x70; 
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[13] = (3 << 5);
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[14] = (unsigned char)
+(1 |
+                                                                     (BX_SELECTED_DRIVE(channel).cdrom.locked ? (1 << 1) : 0) |
+                                                                     (1 << 3) |
+                                                                     (1 << 5));
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[15] = 0x00;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[16] = (706 >> 8) & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[17] = 706 & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[18] = 0;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[19] = 2;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[20] = (512 >> 8) & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[21] = 512 & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[22] = (706 >> 8) & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[23] = 706 & 0xff;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[24] = 0;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[25] = 0;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[26] = 0;
+                                                             BX_SELECTED_CONTROLLER(channel).buffer[27] = 0;
+                                                             ready_to_send_atapi(channel);
+                                                             break;
+
+                                                     case 0x0d: // CD-ROM
+                                                     case 0x0e: // CD-ROM audio control
+                                                     case 0x3f: // all
+                                                           BX_ERROR(("cdrom: MODE SENSE (curr), code=%x"
+                                                                     " not implemented yet",
+                                                                    PageCode));
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                           break;
+
+                                                     default:
+                                                           // not implemeted by this device
+                                                           BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+                                                                     " not implemented by device",
+                                                                     PC, PageCode));
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                           break;
+                                               }
+                                               break;
+
+                                         case 0x1: // changeable values
+                                               switch (PageCode) {
+                                                     case 0x01: // error recovery
+                                                     case 0x0d: // CD-ROM
+                                                     case 0x0e: // CD-ROM audio control
+                                                     case 0x2a: // CD-ROM capabilities & mech. status
+                                                     case 0x3f: // all
+                                                           BX_ERROR(("cdrom: MODE SENSE (chg), code=%x"
+                                                                     " not implemented yet",
+                                                                    PageCode));
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                           break;
+
+                                                     default:
+                                                           // not implemeted by this device
+                                                           BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+                                                                     " not implemented by device",
+                                                                     PC, PageCode));
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                           break;
+                                               }
+                                               break;
+
+                                         case 0x2: // default values
+                                               switch (PageCode) {
+                                                     case 0x01: // error recovery
+                                                     case 0x0d: // CD-ROM
+                                                     case 0x0e: // CD-ROM audio control
+                                                     case 0x2a: // CD-ROM capabilities & mech. status
+                                                     case 0x3f: // all
+                                                           BX_PANIC(("cdrom: MODE SENSE (dflt), code=%x",
+                                                                    PageCode));
+                                                           break;
+
+                                                     default:
+                                                           // not implemeted by this device
+                                                           BX_INFO(("cdrom: MODE SENSE PC=%x, PageCode=%x,"
+                                                                     " not implemented by device",
+                                                                     PC, PageCode));
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                           break;
+                                               }
+                                               break;
+
+                                         case 0x3: // saved values not implemented
+                                               atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
+                                               raise_interrupt(channel);
+                                               break;
+
+                                         default:
+                                               BX_PANIC(("Should not get here!"));
+                                               break;
+                                   }
+                             }
+                             break;
+
+                             case 0x12: { // inquiry
+                                   uint8 alloc_length = BX_SELECTED_CONTROLLER(channel).buffer[4];
+
+                                   init_send_atapi_command(channel, atapi_command, 36, alloc_length);
+
+                                   BX_SELECTED_CONTROLLER(channel).buffer[0] = 0x05; // CD-ROM
+                                   BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x80; // Removable
+                                   BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x00; // ISO, ECMA, ANSI version
+                                   BX_SELECTED_CONTROLLER(channel).buffer[3] = 0x21; // ATAPI-2, as specified
+                                   BX_SELECTED_CONTROLLER(channel).buffer[4] = 31; // additional length (total 36)
+                                   BX_SELECTED_CONTROLLER(channel).buffer[5] = 0x00; // reserved
+                                   BX_SELECTED_CONTROLLER(channel).buffer[6] = 0x00; // reserved
+                                   BX_SELECTED_CONTROLLER(channel).buffer[7] = 0x00; // reserved
+
+                                   // Vendor ID
+                                   const char* vendor_id = "VTAB    ";
+                                    int i;
+                                   for (i = 0; i < 8; i++)
+                                         BX_SELECTED_CONTROLLER(channel).buffer[8+i] = vendor_id[i];
+
+                                   // Product ID
+                                   const char* product_id = "Turbo CD-ROM    ";
+                                   for (i = 0; i < 16; i++)
+                                         BX_SELECTED_CONTROLLER(channel).buffer[16+i] = product_id[i];
+
+                                   // Product Revision level
+                                   const char* rev_level = "1.0 ";
+                                   for (i = 0; i < 4; i++)
+                                         BX_SELECTED_CONTROLLER(channel).buffer[32+i] = rev_level[i];
+
+                                   ready_to_send_atapi(channel);
+                             }
+                             break;
+
+                             case 0x25: { // read cd-rom capacity
+                                   // no allocation length???
+                                   init_send_atapi_command(channel, atapi_command, 8, 8);
+
+                                   if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         uint32 capacity = BX_SELECTED_DRIVE(channel).cdrom.capacity;
+                                         BX_INFO(("Capacity is %d sectors (%d bytes)", capacity, capacity * 2048));
+                                         BX_SELECTED_CONTROLLER(channel).buffer[0] = (capacity >> 24) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[1] = (capacity >> 16) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[2] = (capacity >> 8) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[3] = (capacity >> 0) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[4] = (2048 >> 24) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[5] = (2048 >> 16) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[6] = (2048 >> 8) & 0xff;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[7] = (2048 >> 0) & 0xff;
+                                         ready_to_send_atapi(channel);
+                                   } else {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                         raise_interrupt(channel);
+                                   }
+                             }
+                             break;
+
+                             case 0xbe: { // read cd
+                                   if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         BX_ERROR(("Read CD with CD present not implemented"));
+                                         atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+                                         raise_interrupt(channel);
+                                   } else {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                         raise_interrupt(channel);
+                                   }
+                             }
+                             break;
+
+                             case 0x43: { // read toc
+                                   if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+#ifdef LOWLEVEL_CDROM
+                                         bool msf = (BX_SELECTED_CONTROLLER(channel).buffer[1] >> 1) & 1;
+                                         uint8 starting_track = BX_SELECTED_CONTROLLER(channel).buffer[6];
+#endif
+                                         uint16 alloc_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+
+                                         uint8 format = (BX_SELECTED_CONTROLLER(channel).buffer[9] >> 6);
+                                          int i;
+                                         switch (format) {
+                                               case 0:
+#ifdef LOWLEVEL_CDROM
+                                                     int toc_length;
+                                                     if (!(BX_SELECTED_DRIVE(channel).cdrom.cd->read_toc(BX_SELECTED_CONTROLLER(channel).buffer,
+                                                                                      &toc_length, msf, starting_track))) {
+                                                           atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                                           ASC_INV_FIELD_IN_CMD_PACKET);
+                                                           raise_interrupt(channel);
+                                                     } else {
+                                                           init_send_atapi_command(channel, atapi_command, toc_length, alloc_length);
+                                                           ready_to_send_atapi(channel);
+                                                     }
+#else
+                                                     BX_PANIC(("LOWLEVEL_CDROM not defined"));
+#endif
+                                                     break;
+
+                                               case 1:
+                                                     // multi session stuff. we ignore this and emulate a single session only
+                                                     init_send_atapi_command(channel, atapi_command, 12, alloc_length);
+
+                                                     BX_SELECTED_CONTROLLER(channel).buffer[0] = 0;
+                                                     BX_SELECTED_CONTROLLER(channel).buffer[1] = 0x0a;
+                                                     BX_SELECTED_CONTROLLER(channel).buffer[2] = 1;
+                                                     BX_SELECTED_CONTROLLER(channel).buffer[3] = 1;
+                                                     for (i = 0; i < 8; i++)
+                                                           BX_SELECTED_CONTROLLER(channel).buffer[4+i] = 0;
+
+                                                     ready_to_send_atapi(channel);
+                                                     break;
+
+                                               case 2:
+                                               default:
+                                                     BX_PANIC(("(READ TOC) Format %d not supported", format));
+                                                     break;
+                                         }
+                                   } else {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                         raise_interrupt(channel);
+                                   }
+                             }
+                             break;
+
+                             case 0x28: // read (10)
+                             case 0xa8: // read (12)
+                                        { 
+
+                                   uint32 transfer_length;
+                                   if (atapi_command == 0x28)
+                                         transfer_length = read_16bit(BX_SELECTED_CONTROLLER(channel).buffer + 7);
+                                   else
+                                         transfer_length = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 6);
+
+                                   uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2);
+
+                                   if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                         raise_interrupt(channel);
+                                         break;
+                                   }
+
+                                   if (transfer_length == 0) {
+                                         atapi_cmd_nop(channel);
+                                         raise_interrupt(channel);
+                                         BX_INFO(("READ(%d) with transfer length 0, ok", atapi_command==0x28?10:12));
+                                         break;
+                                   }
+
+                                   if (lba + transfer_length > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
+                                         atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+                                         raise_interrupt(channel);
+                                         break;
+                                   }
+
+                                   BX_DEBUG(("cdrom: READ (%d) LBA=%d LEN=%d", atapi_command==0x28?10:12, lba, transfer_length));
+
+                                   // handle command
+                                   init_send_atapi_command(channel, atapi_command, transfer_length * 2048,
+                                                           transfer_length * 2048, true);
+                                   BX_SELECTED_DRIVE(channel).cdrom.remaining_blocks = transfer_length;
+                                   BX_SELECTED_DRIVE(channel).cdrom.next_lba = lba;
+                                   ready_to_send_atapi(channel);
+                             }
+                             break;
+
+                               case 0x2b: { // seek
+                                       uint32 lba = read_32bit(BX_SELECTED_CONTROLLER(channel).buffer + 2);
+                                       if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                               atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                               raise_interrupt(channel);
+                                               break;
+                                       }
+
+                                       if (lba > BX_SELECTED_DRIVE(channel).cdrom.capacity) {
+                                               atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
+                                               raise_interrupt(channel);
+                                               break;
+                                       }
+                                       BX_INFO(("cdrom: SEEK (ignored)"));
+                                       atapi_cmd_nop(channel);
+                                       raise_interrupt(channel);
+                               }
+                               break;
+
+                             case 0x1e: { // prevent/allow medium removal
+                                   if (BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         BX_SELECTED_DRIVE(channel).cdrom.locked = BX_SELECTED_CONTROLLER(channel).buffer[4] & 1;
+                                         atapi_cmd_nop(channel);
+                                   } else {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                   }
+                                   raise_interrupt(channel);
+                             }
+                             break;
+
+                             case 0x42: { // read sub-channel
+                                   bool msf = get_packet_field(channel,1, 1, 1);
+                                   bool sub_q = get_packet_field(channel,2, 6, 1);
+                                   uint8 data_format = get_packet_byte(channel,3);
+                                   uint8 track_number = get_packet_byte(channel,6);
+                                   uint16 alloc_length = get_packet_word(channel,7);
+                                    UNUSED(msf);
+                                    UNUSED(data_format);
+                                    UNUSED(track_number);
+
+                                   if (!BX_SELECTED_DRIVE(channel).cdrom.ready) {
+                                         atapi_cmd_error(channel, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                                         raise_interrupt(channel);
+                                   } else {
+                                         BX_SELECTED_CONTROLLER(channel).buffer[0] = 0;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[1] = 0; // audio not supported
+                                         BX_SELECTED_CONTROLLER(channel).buffer[2] = 0;
+                                         BX_SELECTED_CONTROLLER(channel).buffer[3] = 0;
+
+                                         int ret_len = 4; // header size
+
+                                         if (sub_q) { // !sub_q == header only
+                                               BX_ERROR(("Read sub-channel with SubQ not implemented"));
+                                               atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST,
+                                                               ASC_INV_FIELD_IN_CMD_PACKET);
+                                           raise_interrupt(channel);
+                                         }
+
+                                         init_send_atapi_command(channel, atapi_command, ret_len, alloc_length);
+                                         ready_to_send_atapi(channel);
+                                   }
+                             }
+                             break;
+
+                             case 0x51: { // read disc info
+                                // no-op to keep the Linux CD-ROM driver happy
+                               atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+                               raise_interrupt(channel);
+                             }
+                             break;
+
+                             case 0x55: // mode select
+                             case 0xa6: // load/unload cd
+                             case 0x4b: // pause/resume
+                             case 0x45: // play audio
+                             case 0x47: // play audio msf
+                             case 0xbc: // play cd
+                             case 0xb9: // read cd msf
+                             case 0x44: // read header
+                             case 0xba: // scan
+                             case 0xbb: // set cd speed
+                             case 0x4e: // stop play/scan
+                             case 0x46: // ???
+                             case 0x4a: // ???
+                               BX_ERROR(("ATAPI command 0x%x not implemented yet",
+                                         atapi_command));
+                               atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+                               raise_interrupt(channel);
+                               break;
+                             default:
+                                   BX_PANIC(("Unknown ATAPI command 0x%x (%d)",
+                                            atapi_command, atapi_command));
+                                    // We'd better signal the error if the user chose to continue
+                                   atapi_cmd_error(channel, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
+                                   raise_interrupt(channel);
+                                   break;
+                       }
+                 }
+
+                 break;
+
+        default:
+          BX_PANIC(("IO write(0x%04x): current command is %02xh", address,
+            (unsigned) BX_SELECTED_CONTROLLER(channel).current_command));
+        }
+      break;
+
+    case 0x01: // hard disk write precompensation 0x1f1
+         WRITE_FEATURES(channel,value);
+         if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom)) {
+               if (value == 0xff)
+                     BX_INFO(("no precompensation {%s}", BX_SELECTED_TYPE_STRING(channel)));
+               else
+                     BX_INFO(("precompensation value %02x {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+         }
+      break;
+
+    case 0x02: // hard disk sector count 0x1f2
+         WRITE_SECTOR_COUNT(channel,value);
+         if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+               BX_INFO(("sector count = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+         break;
+
+    case 0x03: // hard disk sector number 0x1f3
+         WRITE_SECTOR_NUMBER(channel,value);
+         if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+               BX_INFO(("sector number = %u {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+      break;
+
+    case 0x04: // hard disk cylinder low 0x1f4
+         WRITE_CYLINDER_LOW(channel,value);
+         if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+               BX_INFO(("cylinder low = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+         break;
+
+    case 0x05: // hard disk cylinder high 0x1f5
+         WRITE_CYLINDER_HIGH(channel,value);
+         if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+               BX_INFO(("cylinder high = %02xh {%s}", (unsigned) value, BX_SELECTED_TYPE_STRING(channel)));
+         break;
+
+    case 0x06: // hard disk drive and head register 0x1f6
+      // b7 Extended data field for ECC
+      // b6/b5: Used to be sector size.  00=256,01=512,10=1024,11=128
+      //   Since 512 was always used, bit 6 was taken to mean LBA mode:
+      //     b6 1=LBA mode, 0=CHS mode
+      //     b5 1
+      // b4: DRV
+      // b3..0 HD3..HD0
+      {
+      if ( (value & 0xa0) != 0xa0 ) // 1x1xxxxx
+        BX_INFO(("IO write 0x%04x (%02x): not 1x1xxxxxb", address, (unsigned) value));
+      Bit32u drvsel = BX_HD_THIS channels[channel].drive_select = (value >> 4) & 0x01;
+      WRITE_HEAD_NO(channel,value & 0xf);
+      if (BX_SELECTED_CONTROLLER(channel).lba_mode == 0 && ((value >> 6) & 1) == 1)
+        BX_DEBUG(("enabling LBA mode"));
+      WRITE_LBA_MODE(channel,(value >> 6) & 1);
+      if (!BX_SELECTED_IS_PRESENT(channel)) {
+        BX_ERROR (("device set to %d which does not exist",drvsel));
+        BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // aborted
+        BX_SELECTED_CONTROLLER(channel).status.err = 1;
+        }
+      break;
+      }
+
+    case 0x07: // hard disk command 0x1f7
+         // (mch) Writes to the command register with drive_select != 0
+         // are ignored if no secondary device is present
+      if ((BX_SLAVE_SELECTED(channel)) && (!BX_SLAVE_IS_PRESENT(channel)))
+           break;
+      // Writes to the command register clear the IRQ
+      DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+
+      if (BX_SELECTED_CONTROLLER(channel).status.busy)
+        BX_PANIC(("hard disk: command sent, controller BUSY"));
+      if ( (value & 0xf0) == 0x10 )
+        value = 0x10;
+      switch (value) {
+
+        case 0x10: // CALIBRATE DRIVE
+         if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("calibrate drive issued to non-disk"));
+          if (!BX_SELECTED_IS_PRESENT(channel)) {
+            BX_SELECTED_CONTROLLER(channel).error_register = 0x02; // Track 0 not found
+            BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err = 1;
+           raise_interrupt(channel);
+            BX_INFO(("calibrate drive: disk ata%d-%d not present", channel, BX_SLAVE_SELECTED(channel)));
+            break;
+            }
+
+          /* move head to cylinder 0, issue IRQ */
+          BX_SELECTED_CONTROLLER(channel).error_register = 0;
+          BX_SELECTED_CONTROLLER(channel).cylinder_no = 0;
+          BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+          BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+          BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+          BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+          BX_SELECTED_CONTROLLER(channel).status.err = 0;
+         raise_interrupt(channel);
+          break;
+
+        case 0x20: // READ MULTIPLE SECTORS, with retries
+        case 0x21: // READ MULTIPLE SECTORS, without retries
+          /* update sector_no, always points to current sector
+           * after each sector is read to buffer, DRQ bit set and issue IRQ 
+           * if interrupt handler transfers all data words into main memory,
+           * and more sectors to read, then set BSY bit again, clear DRQ and
+           * read next sector into buffer
+           * sector count of 0 means 256 sectors
+           */
+
+         if (!BX_SELECTED_IS_HD(channel)) {
+               BX_ERROR(("read multiple issued to non-disk"));
+               command_aborted(channel, value);
+               break;
+         }
+
+          BX_SELECTED_CONTROLLER(channel).current_command = value;
+
+         // Lose98 accesses 0/0/0 in CHS mode
+         if (!BX_SELECTED_CONTROLLER(channel).lba_mode &&
+             !BX_SELECTED_CONTROLLER(channel).head_no &&
+             !BX_SELECTED_CONTROLLER(channel).cylinder_no &&
+             !BX_SELECTED_CONTROLLER(channel).sector_no) {
+               BX_INFO(("Read from 0/0/0, aborting command"));
+               command_aborted(channel, value);
+               break;
+         }
+
+#if TEST_READ_BEYOND_END==2
+         BX_SELECTED_CONTROLLER(channel).cylinder_no += 100000;
+#endif
+         if (!calculate_logical_address(channel, &logical_sector)) {
+           BX_ERROR(("initial read from sector %lu out of bounds, aborting", (unsigned long)logical_sector));
+           command_aborted(channel, value);
+           break;
+         }
+#if TEST_READ_BEYOND_END==3
+         logical_sector += 100000;
+#endif
+         ret=BX_SELECTED_DRIVE(channel).hard_drive->lseek(logical_sector * 512, SEEK_SET);
+          if (ret < 0) {
+            BX_ERROR (("could not lseek() hard drive image file, aborting"));
+           command_aborted(channel, value);
+           break;
+         }
+         ret = BX_SELECTED_DRIVE(channel).hard_drive->read((bx_ptr_t) BX_SELECTED_CONTROLLER(channel).buffer, 512);
+          if (ret < 512) {
+            BX_ERROR(("logical sector was %lu", (unsigned long)logical_sector));
+            BX_ERROR(("could not read() hard drive image file at byte %lu", (unsigned long)logical_sector*512));
+           command_aborted(channel, value);
+           break;
+         }
+
+          BX_SELECTED_CONTROLLER(channel).error_register = 0;
+          BX_SELECTED_CONTROLLER(channel).status.busy  = 0;
+          BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+          BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+          BX_SELECTED_CONTROLLER(channel).status.drq   = 1;
+          BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+          BX_SELECTED_CONTROLLER(channel).status.err   = 0;
+          BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+         raise_interrupt(channel);
+          break;
+
+        case 0x30: /* WRITE SECTORS, with retries */
+          /* update sector_no, always points to current sector
+           * after each sector is read to buffer, DRQ bit set and issue IRQ 
+           * if interrupt handler transfers all data words into main memory,
+           * and more sectors to read, then set BSY bit again, clear DRQ and
+           * read next sector into buffer
+           * sector count of 0 means 256 sectors
+           */
+
+         if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("write multiple issued to non-disk"));
+
+          if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+            BX_PANIC(("write command: BSY bit set"));
+            }
+          BX_SELECTED_CONTROLLER(channel).current_command = value;
+
+          // implicit seek done :^)
+          BX_SELECTED_CONTROLLER(channel).error_register = 0;
+          BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+          // BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+          BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+          BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+          BX_SELECTED_CONTROLLER(channel).status.err   = 0;
+          BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+          break;
+
+        case 0x90: // EXECUTE DEVICE DIAGNOSTIC
+          if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+            BX_PANIC(("diagnostic command: BSY bit set"));
+            }
+         if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("drive diagnostics issued to non-disk"));
+          BX_SELECTED_CONTROLLER(channel).error_register = 0x81; // Drive 1 failed, no error on drive 0
+          // BX_SELECTED_CONTROLLER(channel).status.busy = 0; // not needed
+          BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+          BX_SELECTED_CONTROLLER(channel).status.err = 0;
+          break;
+
+        case 0x91: // INITIALIZE DRIVE PARAMETERS
+          if (BX_SELECTED_CONTROLLER(channel).status.busy) {
+            BX_PANIC(("init drive parameters command: BSY bit set"));
+            }
+         if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("initialize drive parameters issued to non-disk"));
+          // sets logical geometry of specified drive
+          BX_DEBUG(("init drive params: sec=%u, drive sel=%u, head=%u",
+            (unsigned) BX_SELECTED_CONTROLLER(channel).sector_count,
+            (unsigned) BX_HD_THIS channels[channel].drive_select,
+            (unsigned) BX_SELECTED_CONTROLLER(channel).head_no));
+          if (!BX_SELECTED_IS_PRESENT(channel)) {
+            BX_PANIC(("init drive params: disk ata%d-%d not present", channel, BX_SLAVE_SELECTED(channel)));
+            //BX_SELECTED_CONTROLLER(channel).error_register = 0x12;
+            BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err = 0;
+           raise_interrupt(channel);
+            break;
+         }
+          if (BX_SELECTED_CONTROLLER(channel).sector_count != BX_SELECTED_DRIVE(channel).hard_drive->sectors)
+            BX_PANIC(("init drive params: sector count doesnt match %d!=%d", BX_SELECTED_CONTROLLER(channel).sector_count, BX_SELECTED_DRIVE(channel).hard_drive->sectors));
+          if ( BX_SELECTED_CONTROLLER(channel).head_no != (BX_SELECTED_DRIVE(channel).hard_drive->heads-1) )
+            BX_PANIC(("init drive params: head number doesn't match %d != %d",BX_SELECTED_CONTROLLER(channel).head_no, BX_SELECTED_DRIVE(channel).hard_drive->heads-1));
+          BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+          BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+          BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+          BX_SELECTED_CONTROLLER(channel).status.err = 0;
+         raise_interrupt(channel);
+          break;
+
+        case 0xec: // IDENTIFY DEVICE
+          if (bx_options.OnewHardDriveSupport->get ()) {
+           if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+                 BX_INFO(("Drive ID Command issued : 0xec "));
+
+            if (!BX_SELECTED_IS_PRESENT(channel)) {
+              BX_INFO(("disk ata%d-%d not present, aborting",channel,BX_SLAVE_SELECTED(channel)));
+              command_aborted(channel, value);
+              break;
+              }
+           if (BX_SELECTED_IS_CD(channel)) {
+                 BX_SELECTED_CONTROLLER(channel).head_no        = 0;
+                 BX_SELECTED_CONTROLLER(channel).sector_count   = 1;
+                 BX_SELECTED_CONTROLLER(channel).sector_no      = 1;
+                 BX_SELECTED_CONTROLLER(channel).cylinder_no    = 0xeb14;
+                 command_aborted(channel, 0xec);
+           } else {
+                 BX_SELECTED_CONTROLLER(channel).current_command = value;
+                 BX_SELECTED_CONTROLLER(channel).error_register = 0;
+
+                 // See ATA/ATAPI-4, 8.12
+                 BX_SELECTED_CONTROLLER(channel).status.busy  = 0;
+                 BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+                 BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+                 BX_SELECTED_CONTROLLER(channel).status.drq   = 1;
+                 BX_SELECTED_CONTROLLER(channel).status.err   = 0;
+
+                 BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+                 BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+
+                 BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+                 raise_interrupt(channel);
+                 identify_drive(channel);
+           }
+         }
+          else {
+           BX_INFO(("sent IDENTIFY DEVICE (0xec) to old hard drive"));
+            command_aborted(channel, value);
+         }
+          break;
+
+        case 0xef: // SET FEATURES
+         switch(BX_SELECTED_CONTROLLER(channel).features) {
+           case 0x02: // Enable and
+           case 0x82: //  Disable write cache.
+           case 0xAA: // Enable and
+           case 0x55: //  Disable look-ahead cache.
+           case 0xCC: // Enable and
+           case 0x66: //  Disable reverting to power-on default
+             BX_INFO(("SET FEATURES subcommand 0x%02x not supported by disk.", (unsigned) BX_SELECTED_CONTROLLER(channel).features));
+             command_aborted(channel, value);
+           break;
+
+           default:
+             BX_PANIC(("SET FEATURES with unknown subcommand: 0x%02x", (unsigned) BX_SELECTED_CONTROLLER(channel).features ));
+              // We'd better signal the error if the user chose to continue
+             command_aborted(channel, value);
+         }
+         break;
+
+        case 0x40: // READ VERIFY SECTORS
+          if (bx_options.OnewHardDriveSupport->get ()) {
+           if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("read verify issued to non-disk"));
+            BX_INFO(("Verify Command : 0x40 ! "));
+            BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err = 0;
+           raise_interrupt(channel);
+            }
+          else {
+           BX_INFO(("sent READ VERIFY SECTORS (0x40) to old hard drive"));
+            command_aborted(channel, value);
+         }
+          break;
+
+       case 0xc6: // SET MULTIPLE MODE (mch)
+             if (BX_SELECTED_CONTROLLER(channel).sector_count != 128 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 64 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 32 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 16 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 8 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 4 &&
+                 BX_SELECTED_CONTROLLER(channel).sector_count != 2)
+                   command_aborted(channel, value);
+
+             if (!BX_SELECTED_IS_HD(channel))
+               BX_PANIC(("set multiple mode issued to non-disk"));
+
+             BX_SELECTED_CONTROLLER(channel).sectors_per_block = BX_SELECTED_CONTROLLER(channel).sector_count;
+             BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+             BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+             BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+             BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+             BX_SELECTED_CONTROLLER(channel).status.err = 0;
+             break;
+
+        // ATAPI commands
+        case 0xa1: // IDENTIFY PACKET DEVICE
+             if (BX_SELECTED_IS_CD(channel)) {
+                   BX_SELECTED_CONTROLLER(channel).current_command = value;
+                   BX_SELECTED_CONTROLLER(channel).error_register = 0;
+
+                   BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+                   BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.drq   = 1;
+                   BX_SELECTED_CONTROLLER(channel).status.err   = 0;
+
+                   BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+                   BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+
+                   BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+                   raise_interrupt(channel);
+                   identify_ATAPI_drive(channel);
+             } else {
+                   command_aborted(channel, 0xa1);
+             }
+             break;
+
+        case 0x08: // DEVICE RESET (atapi)
+             if (BX_SELECTED_IS_CD(channel)) {
+                   BX_SELECTED_CONTROLLER(channel).status.busy = 1;
+                   BX_SELECTED_CONTROLLER(channel).error_register &= ~(1 << 7);
+
+                   // device signature
+                   BX_SELECTED_CONTROLLER(channel).head_no        = 0;
+                   BX_SELECTED_CONTROLLER(channel).sector_count   = 1;
+                   BX_SELECTED_CONTROLLER(channel).sector_no      = 1;
+                   BX_SELECTED_CONTROLLER(channel).cylinder_no    = 0xeb14;
+
+                   BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+                   BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+
+             } else {
+               BX_DEBUG(("ATAPI Device Reset on non-cd device"));
+               command_aborted(channel, 0x08);
+             }
+             break;
+
+        case 0xa0: // SEND PACKET (atapi)
+             if (BX_SELECTED_IS_CD(channel)) {
+                   // PACKET
+                   if (BX_SELECTED_CONTROLLER(channel).features & (1 << 0))
+                         BX_PANIC(("PACKET-DMA not supported"));
+                   if (BX_SELECTED_CONTROLLER(channel).features & (1 << 1))
+                         BX_PANIC(("PACKET-overlapped not supported"));
+
+                   // We're already ready!
+                   BX_SELECTED_CONTROLLER(channel).sector_count = 1;
+                   BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+                   BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+                   // serv bit??
+                   BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+                   BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+                   // NOTE: no interrupt here
+                   BX_SELECTED_CONTROLLER(channel).current_command = value;
+                   BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+             } else {
+               command_aborted (channel, 0xa0);
+             }
+             break;
+
+        case 0xa2: // SERVICE (atapi), optional
+             if (BX_SELECTED_IS_CD(channel)) {
+                   BX_PANIC(("ATAPI SERVICE not implemented"));
+             } else {
+               command_aborted (channel, 0xa2);
+             }
+             break;
+
+        // power management
+       case 0xe5: // CHECK POWER MODE
+         BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+         BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+         BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+         BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+         BX_SELECTED_CONTROLLER(channel).status.err = 0;
+         BX_SELECTED_CONTROLLER(channel).sector_count = 0xff; // Active or Idle mode
+         raise_interrupt(channel);
+         break;
+
+       case 0x70:  // SEEK (cgs)
+         if (BX_SELECTED_IS_HD(channel)) {
+           BX_DEBUG(("write cmd 0x70 (SEEK) executing"));
+            if (!calculate_logical_address(channel, &logical_sector)) {
+             BX_ERROR(("initial seek to sector %lu out of bounds, aborting", (unsigned long)logical_sector));
+              command_aborted(channel, value);
+             break;
+           }
+            BX_SELECTED_CONTROLLER(channel).error_register = 0;
+            BX_SELECTED_CONTROLLER(channel).status.busy  = 0;
+            BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+            BX_SELECTED_CONTROLLER(channel).status.seek_complete = 1;
+            BX_SELECTED_CONTROLLER(channel).status.drq   = 0;
+            BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+            BX_SELECTED_CONTROLLER(channel).status.err   = 0;
+            BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+           BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq));
+           BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq));
+           BX_DEBUG(("SEEK completed.  error_register = %02x", BX_SELECTED_CONTROLLER(channel).error_register));
+           raise_interrupt(channel);
+           BX_DEBUG(("SEEK interrupt completed"));
+          } else {
+           BX_ERROR(("write cmd 0x70 (SEEK) not supported for non-disk"));
+           command_aborted(channel, 0x70); 
+         }
+          break;
+
+
+
+       // List all the write operations that are defined in the ATA/ATAPI spec
+       // that we don't support.  Commands that are listed here will cause a
+       // BX_ERROR, which is non-fatal, and the command will be aborted.
+       case 0x22: BX_ERROR(("write cmd 0x22 (READ LONG) not supported")); command_aborted(channel, 0x22); break;
+       case 0x23: BX_ERROR(("write cmd 0x23 (READ LONG NO RETRY) not supported")); command_aborted(channel, 0x23); break;
+       case 0x24: BX_ERROR(("write cmd 0x24 (READ SECTORS EXT) not supported"));command_aborted(channel, 0x24); break;
+       case 0x25: BX_ERROR(("write cmd 0x25 (READ DMA EXT) not supported"));command_aborted(channel, 0x25); break;
+       case 0x26: BX_ERROR(("write cmd 0x26 (READ DMA QUEUED EXT) not supported"));command_aborted(channel, 0x26); break;
+       case 0x27: BX_ERROR(("write cmd 0x27 (READ NATIVE MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x27); break;
+       case 0x29: BX_ERROR(("write cmd 0x29 (READ MULTIPLE EXT) not supported"));command_aborted(channel, 0x29); break;
+       case 0x2A: BX_ERROR(("write cmd 0x2A (READ STREAM DMA) not supported"));command_aborted(channel, 0x2A); break;
+       case 0x2B: BX_ERROR(("write cmd 0x2B (READ STREAM PIO) not supported"));command_aborted(channel, 0x2B); break;
+       case 0x2F: BX_ERROR(("write cmd 0x2F (READ LOG EXT) not supported"));command_aborted(channel, 0x2F); break;
+       case 0x31: BX_ERROR(("write cmd 0x31 (WRITE SECTORS NO RETRY) not supported")); command_aborted(channel, 0x31); break;
+       case 0x32: BX_ERROR(("write cmd 0x32 (WRITE LONG) not supported")); command_aborted(channel, 0x32); break;
+       case 0x33: BX_ERROR(("write cmd 0x33 (WRITE LONG NO RETRY) not supported")); command_aborted(channel, 0x33); break;
+       case 0x34: BX_ERROR(("write cmd 0x34 (WRITE SECTORS EXT) not supported"));command_aborted(channel, 0x34); break;
+       case 0x35: BX_ERROR(("write cmd 0x35 (WRITE DMA EXT) not supported"));command_aborted(channel, 0x35); break;
+       case 0x36: BX_ERROR(("write cmd 0x36 (WRITE DMA QUEUED EXT) not supported"));command_aborted(channel, 0x36); break;
+       case 0x37: BX_ERROR(("write cmd 0x37 (SET MAX ADDRESS EXT) not supported"));command_aborted(channel, 0x37); break;
+       case 0x38: BX_ERROR(("write cmd 0x38 (CFA WRITE SECTORS W/OUT ERASE) not supported"));command_aborted(channel, 0x38); break;
+       case 0x39: BX_ERROR(("write cmd 0x39 (WRITE MULTIPLE EXT) not supported"));command_aborted(channel, 0x39); break;
+       case 0x3A: BX_ERROR(("write cmd 0x3A (WRITE STREAM DMA) not supported"));command_aborted(channel, 0x3A); break;
+       case 0x3B: BX_ERROR(("write cmd 0x3B (WRITE STREAM PIO) not supported"));command_aborted(channel, 0x3B); break;
+       case 0x3F: BX_ERROR(("write cmd 0x3F (WRITE LOG EXT) not supported"));command_aborted(channel, 0x3F); break;
+       case 0x41: BX_ERROR(("write cmd 0x41 (READ VERIFY SECTORS NO RETRY) not supported")); command_aborted(channel, 0x41); break;
+       case 0x42: BX_ERROR(("write cmd 0x42 (READ VERIFY SECTORS EXT) not supported"));command_aborted(channel, 0x42); break;
+       case 0x50: BX_ERROR(("write cmd 0x50 (FORMAT TRACK) not supported")); command_aborted(channel, 0x50); break;
+       case 0x51: BX_ERROR(("write cmd 0x51 (CONFIGURE STREAM) not supported"));command_aborted(channel, 0x51); break;
+       case 0x87: BX_ERROR(("write cmd 0x87 (CFA TRANSLATE SECTOR) not supported"));command_aborted(channel, 0x87); break;
+       case 0x92: BX_ERROR(("write cmd 0x92 (DOWNLOAD MICROCODE) not supported"));command_aborted(channel, 0x92); break;
+       case 0x94: BX_ERROR(("write cmd 0x94 (STANDBY IMMEDIATE) not supported")); command_aborted(channel, 0x94); break;
+       case 0x95: BX_ERROR(("write cmd 0x95 (IDLE IMMEDIATE) not supported")); command_aborted(channel, 0x95); break;
+       case 0x96: BX_ERROR(("write cmd 0x96 (STANDBY) not supported")); command_aborted(channel, 0x96); break;
+       case 0x97: BX_ERROR(("write cmd 0x97 (IDLE) not supported")); command_aborted(channel, 0x97); break;
+       case 0x98: BX_ERROR(("write cmd 0x98 (CHECK POWER MODE) not supported")); command_aborted(channel, 0x98); break;
+       case 0x99: BX_ERROR(("write cmd 0x99 (SLEEP) not supported")); command_aborted(channel, 0x99); break;
+       case 0xB0: BX_ERROR(("write cmd 0xB0 (SMART commands) not supported"));command_aborted(channel, 0xB0); break;
+       case 0xB1: BX_ERROR(("write cmd 0xB1 (DEVICE CONFIGURATION commands) not supported"));command_aborted(channel, 0xB1); break;
+       case 0xC0: BX_ERROR(("write cmd 0xC0 (CFA ERASE SECTORS) not supported"));command_aborted(channel, 0xC0); break;
+       case 0xC4: BX_ERROR(("write cmd 0xC4 (READ MULTIPLE) not supported"));command_aborted(channel, 0xC4); break;
+       case 0xC5: BX_ERROR(("write cmd 0xC5 (WRITE MULTIPLE) not supported"));command_aborted(channel, 0xC5); break;
+       case 0xC7: BX_ERROR(("write cmd 0xC7 (READ DMA QUEUED) not supported"));command_aborted(channel, 0xC7); break;
+       case 0xC8: BX_ERROR(("write cmd 0xC8 (READ DMA) not supported"));command_aborted(channel, 0xC8); break;
+       case 0xC9: BX_ERROR(("write cmd 0xC9 (READ DMA NO RETRY) not supported")); command_aborted(channel, 0xC9); break;
+       case 0xCA: BX_ERROR(("write cmd 0xCA (WRITE DMA) not supported"));command_aborted(channel, 0xCA); break;
+       case 0xCC: BX_ERROR(("write cmd 0xCC (WRITE DMA QUEUED) not supported"));command_aborted(channel, 0xCC); break;
+       case 0xCD: BX_ERROR(("write cmd 0xCD (CFA WRITE MULTIPLE W/OUT ERASE) not supported"));command_aborted(channel, 0xCD); break;
+       case 0xD1: BX_ERROR(("write cmd 0xD1 (CHECK MEDIA CARD TYPE) not supported"));command_aborted(channel, 0xD1); break;
+       case 0xDA: BX_ERROR(("write cmd 0xDA (GET MEDIA STATUS) not supported"));command_aborted(channel, 0xDA); break;
+       case 0xDE: BX_ERROR(("write cmd 0xDE (MEDIA LOCK) not supported"));command_aborted(channel, 0xDE); break;
+       case 0xDF: BX_ERROR(("write cmd 0xDF (MEDIA UNLOCK) not supported"));command_aborted(channel, 0xDF); break;
+       case 0xE0: BX_ERROR(("write cmd 0xE0 (STANDBY IMMEDIATE) not supported"));command_aborted(channel, 0xE0); break;
+       case 0xE1: BX_ERROR(("write cmd 0xE1 (IDLE IMMEDIATE) not supported"));command_aborted(channel, 0xE1); break;
+       case 0xE2: BX_ERROR(("write cmd 0xE2 (STANDBY) not supported"));command_aborted(channel, 0xE2); break;
+       case 0xE3: BX_ERROR(("write cmd 0xE3 (IDLE) not supported"));command_aborted(channel, 0xE3); break;
+       case 0xE4: BX_ERROR(("write cmd 0xE4 (READ BUFFER) not supported"));command_aborted(channel, 0xE4); break;
+       case 0xE6: BX_ERROR(("write cmd 0xE6 (SLEEP) not supported"));command_aborted(channel, 0xE6); break;
+        case 0xE7: BX_ERROR(("write cmd 0xE7 (FLUSH CACHE) not supported"));command_aborted(channel, 0xE7); break;
+       case 0xE8: BX_ERROR(("write cmd 0xE8 (WRITE BUFFER) not supported"));command_aborted(channel, 0xE8); break;
+       case 0xEA: BX_ERROR(("write cmd 0xEA (FLUSH CACHE EXT) not supported"));command_aborted(channel, 0xEA); break;
+       case 0xED: BX_ERROR(("write cmd 0xED (MEDIA EJECT) not supported"));command_aborted(channel, 0xED); break;
+       case 0xF1: BX_ERROR(("write cmd 0xF1 (SECURITY SET PASSWORD) not supported"));command_aborted(channel, 0xF1); break;
+       case 0xF2: BX_ERROR(("write cmd 0xF2 (SECURITY UNLOCK) not supported"));command_aborted(channel, 0xF2); break;
+       case 0xF3: BX_ERROR(("write cmd 0xF3 (SECURITY ERASE PREPARE) not supported"));command_aborted(channel, 0xF3); break;
+       case 0xF4: BX_ERROR(("write cmd 0xF4 (SECURITY ERASE UNIT) not supported"));command_aborted(channel, 0xF4); break;
+       case 0xF5: BX_ERROR(("write cmd 0xF5 (SECURITY FREEZE LOCK) not supported"));command_aborted(channel, 0xF5); break;
+       case 0xF6: BX_ERROR(("write cmd 0xF6 (SECURITY DISABLE PASSWORD) not supported"));command_aborted(channel, 0xF6); break;
+       case 0xF8: BX_ERROR(("write cmd 0xF8 (READ NATIVE MAX ADDRESS) not supported"));command_aborted(channel, 0xF8); break;
+       case 0xF9: BX_ERROR(("write cmd 0xF9 (SET MAX ADDRESS) not supported"));command_aborted(channel, 0xF9); break;
+
+       default:
+          BX_PANIC(("IO write(0x%04x): command 0x%02x", address, (unsigned) value));
+         // if user foolishly decides to continue, abort the command
+         // so that the software knows the drive didn't understand it.
+          command_aborted(channel, value);
+        }
+      break;
+
+    case 0x16: // hard disk adapter control 0x3f6
+         // (mch) Even if device 1 was selected, a write to this register
+         // goes to device 0 (if device 1 is absent)
+               
+         prev_control_reset = BX_SELECTED_CONTROLLER(channel).control.reset;
+         BX_HD_THIS channels[channel].drives[0].controller.control.reset         = value & 0x04;
+         BX_HD_THIS channels[channel].drives[1].controller.control.reset         = value & 0x04;
+         // CGS: was: BX_SELECTED_CONTROLLER(channel).control.disable_irq    = value & 0x02;
+         BX_HD_THIS channels[channel].drives[0].controller.control.disable_irq = value & 0x02;
+         BX_HD_THIS channels[channel].drives[1].controller.control.disable_irq = value & 0x02;
+
+      BX_DEBUG(( "adpater control reg: reset controller = %d",
+        (unsigned) (BX_SELECTED_CONTROLLER(channel).control.reset) ? 1 : 0 ));
+      BX_DEBUG(( "adpater control reg: disable_irq(X) = %d",
+        (unsigned) (BX_SELECTED_CONTROLLER(channel).control.disable_irq) ? 1 : 0 ));
+
+         if (!prev_control_reset && BX_SELECTED_CONTROLLER(channel).control.reset) {
+               // transition from 0 to 1 causes all drives to reset
+               BX_DEBUG(("hard drive: RESET"));
+
+               // (mch) Set BSY, drive not ready
+               for (int id = 0; id < 2; id++) {
+                     BX_CONTROLLER(channel,id).status.busy           = 1;
+                     BX_CONTROLLER(channel,id).status.drive_ready    = 0;
+                     BX_CONTROLLER(channel,id).reset_in_progress     = 1;
+
+                     BX_CONTROLLER(channel,id).status.write_fault    = 0;
+                     BX_CONTROLLER(channel,id).status.seek_complete  = 1;
+                     BX_CONTROLLER(channel,id).status.drq            = 0;
+                     BX_CONTROLLER(channel,id).status.corrected_data = 0;
+                     BX_CONTROLLER(channel,id).status.err            = 0;
+
+                     BX_CONTROLLER(channel,id).error_register = 0x01; // diagnostic code: no error
+
+                     BX_CONTROLLER(channel,id).current_command = 0x00;
+                     BX_CONTROLLER(channel,id).buffer_index = 0;
+
+                     BX_CONTROLLER(channel,id).sectors_per_block = 0x80;
+                     BX_CONTROLLER(channel,id).lba_mode          = 0;
+
+                     BX_CONTROLLER(channel,id).control.disable_irq = 0;
+                     DEV_pic_lower_irq(BX_HD_THIS channels[channel].irq);
+               }
+         } else if (BX_SELECTED_CONTROLLER(channel).reset_in_progress &&
+                    !BX_SELECTED_CONTROLLER(channel).control.reset) {
+               // Clear BSY and DRDY
+               BX_DEBUG(("Reset complete {%s}", BX_SELECTED_TYPE_STRING(channel)));
+               for (int id = 0; id < 2; id++) {
+                     BX_CONTROLLER(channel,id).status.busy           = 0;
+                     BX_CONTROLLER(channel,id).status.drive_ready    = 1;
+                     BX_CONTROLLER(channel,id).reset_in_progress     = 0;
+
+                     // Device signature
+                     if (BX_DRIVE_IS_HD(channel,id)) {
+                           BX_CONTROLLER(channel,id).head_no        = 0;
+                           BX_CONTROLLER(channel,id).sector_count   = 1;
+                           BX_CONTROLLER(channel,id).sector_no      = 1;
+                           BX_CONTROLLER(channel,id).cylinder_no    = 0;
+                     } else {
+                           BX_CONTROLLER(channel,id).head_no        = 0;
+                           BX_CONTROLLER(channel,id).sector_count   = 1;
+                           BX_CONTROLLER(channel,id).sector_no      = 1;
+                           BX_CONTROLLER(channel,id).cylinder_no    = 0xeb14;
+                     }
+               }
+         }
+           BX_DEBUG(("s[0].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[0]).controller.control.disable_irq));
+           BX_DEBUG(("s[1].controller.control.disable_irq = %02x", (BX_HD_THIS channels[channel].drives[1]).controller.control.disable_irq));
+         break;
+
+    default:
+      BX_PANIC(("hard drive: io write to address %x = %02x",
+        (unsigned) address, (unsigned) value));
+    }
+}
+
+  void
+bx_hard_drive_c::close_harddrive(void)
+{
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if(BX_HD_THIS channels[channel].drives[0].hard_drive != NULL)
+      BX_HD_THIS channels[channel].drives[0].hard_drive->close();
+    if(BX_HD_THIS channels[channel].drives[1].hard_drive != NULL)
+      BX_HD_THIS channels[channel].drives[1].hard_drive->close();
+  }
+}
+
+
+  bx_bool BX_CPP_AttrRegparmN(2)
+bx_hard_drive_c::calculate_logical_address(Bit8u channel, off_t *sector)
+{
+      off_t logical_sector;
+
+      if (BX_SELECTED_CONTROLLER(channel).lba_mode) {
+            //bx_printf ("disk: calculate: %d %d %d\n", ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no), ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no), (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no);
+           logical_sector = ((Bit32u)BX_SELECTED_CONTROLLER(channel).head_no) << 24 |
+                 ((Bit32u)BX_SELECTED_CONTROLLER(channel).cylinder_no) << 8 |
+                 (Bit32u)BX_SELECTED_CONTROLLER(channel).sector_no;
+            //bx_printf ("disk: result: %u\n", logical_sector);
+      } else
+           logical_sector = (BX_SELECTED_CONTROLLER(channel).cylinder_no * BX_SELECTED_DRIVE(channel).hard_drive->heads *
+                             BX_SELECTED_DRIVE(channel).hard_drive->sectors) +
+                 (BX_SELECTED_CONTROLLER(channel).head_no * BX_SELECTED_DRIVE(channel).hard_drive->sectors) +
+                 (BX_SELECTED_CONTROLLER(channel).sector_no - 1);
+
+      Bit32u sector_count= 
+          (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->cylinders * 
+           (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->heads * 
+           (Bit32u)BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+      if (logical_sector >= sector_count) {
+            BX_ERROR (("calc_log_addr: out of bounds (%d/%d)", (Bit32u)logical_sector, sector_count));
+           return false;
+      }
+      *sector = logical_sector;
+      return true;
+}
+
+  void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::increment_address(Bit8u channel)
+{
+      BX_SELECTED_CONTROLLER(channel).sector_count--;
+
+      if (BX_SELECTED_CONTROLLER(channel).lba_mode) {
+           off_t current_address;
+           calculate_logical_address(channel, &current_address);
+           current_address++;
+           BX_SELECTED_CONTROLLER(channel).head_no = (Bit8u)((current_address >> 24) & 0xf);
+           BX_SELECTED_CONTROLLER(channel).cylinder_no = (Bit16u)((current_address >> 8) & 0xffff);
+           BX_SELECTED_CONTROLLER(channel).sector_no = (Bit8u)((current_address) & 0xff);
+      } else {
+            BX_SELECTED_CONTROLLER(channel).sector_no++;
+            if (BX_SELECTED_CONTROLLER(channel).sector_no > BX_SELECTED_DRIVE(channel).hard_drive->sectors) {
+                 BX_SELECTED_CONTROLLER(channel).sector_no = 1;
+                 BX_SELECTED_CONTROLLER(channel).head_no++;
+                 if (BX_SELECTED_CONTROLLER(channel).head_no >= BX_SELECTED_DRIVE(channel).hard_drive->heads) {
+                       BX_SELECTED_CONTROLLER(channel).head_no = 0;
+                       BX_SELECTED_CONTROLLER(channel).cylinder_no++;
+                       if (BX_SELECTED_CONTROLLER(channel).cylinder_no >= BX_SELECTED_DRIVE(channel).hard_drive->cylinders)
+                             BX_SELECTED_CONTROLLER(channel).cylinder_no = BX_SELECTED_DRIVE(channel).hard_drive->cylinders - 1;
+                 }
+           }
+      }
+}
+
+  void
+bx_hard_drive_c::identify_ATAPI_drive(Bit8u channel)
+{
+  unsigned i;
+
+  BX_SELECTED_DRIVE(channel).id_drive[0] = (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0); // Removable CDROM, 50us response, 12 byte packets
+
+  for (i = 1; i <= 9; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  const char* serial_number = " VT00001\0\0\0\0\0\0\0\0\0\0\0\0";
+  for (i = 0; i < 10; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) |
+             serial_number[i*2 + 1];
+  }
+
+  for (i = 20; i <= 22; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  const char* firmware = "ALPHA1  ";
+  for (i = 0; i < strlen(firmware)/2; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) |
+             firmware[i*2 + 1];
+  }
+  BX_ASSERT((23+i) == 27);
+  
+  for (i = 0; i < strlen((char *) BX_SELECTED_MODEL(channel))/2; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) |
+             BX_SELECTED_MODEL(channel)[i*2 + 1];
+  }
+  BX_ASSERT((27+i) == 47);
+
+  BX_SELECTED_DRIVE(channel).id_drive[47] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[48] = 1; // 32 bits access
+
+  BX_SELECTED_DRIVE(channel).id_drive[49] = (1 << 9); // LBA supported
+
+  BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[51] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[52] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[53] = 3; // words 64-70, 54-58 valid
+
+  for (i = 54; i <= 62; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // copied from CFA540A
+  BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff)
+  BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO
+  BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4;
+  BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4;
+  BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c;
+  BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4;
+
+  BX_SELECTED_DRIVE(channel).id_drive[69] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[70] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[71] = 30; // faked
+  BX_SELECTED_DRIVE(channel).id_drive[72] = 30; // faked
+  BX_SELECTED_DRIVE(channel).id_drive[73] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[74] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[75] = 0;
+
+  for (i = 76; i <= 79; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[80] = 0x1e; // supports up to ATA/ATAPI-4
+  BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[82] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[83] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[84] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[85] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[87] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[88] = 0;
+
+  for (i = 89; i <= 126; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[127] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[128] = 0;
+
+  for (i = 129; i <= 159; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  for (i = 160; i <= 255; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // now convert the id_drive array (native 256 word format) to
+  // the controller buffer (512 bytes)
+  Bit16u temp16;
+  for (i = 0; i <= 255; i++) {
+       temp16 = BX_SELECTED_DRIVE(channel).id_drive[i];
+       BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff;
+       BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8;
+  }
+}
+
+  void
+bx_hard_drive_c::identify_drive(Bit8u channel)
+{
+  unsigned i;
+  Bit32u temp32;
+  Bit16u temp16;
+
+#if defined(CONNER_CFA540A)
+  BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0c5a;
+  BX_SELECTED_DRIVE(channel).id_drive[1] = 0x0418;
+  BX_SELECTED_DRIVE(channel).id_drive[2] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+  BX_SELECTED_DRIVE(channel).id_drive[4] = 0x9fb7;
+  BX_SELECTED_DRIVE(channel).id_drive[5] = 0x0289;
+  BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+  BX_SELECTED_DRIVE(channel).id_drive[7] = 0x0030;
+  BX_SELECTED_DRIVE(channel).id_drive[8] = 0x000a;
+  BX_SELECTED_DRIVE(channel).id_drive[9] = 0x0000;
+
+  char* serial_number = " CA00GSQ\0\0\0\0\0\0\0\0\0\0\0\0";
+  for (i = 0; i < 10; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[10+i] = (serial_number[i*2] << 8) |
+             serial_number[i*2 + 1];
+  }
+
+  BX_SELECTED_DRIVE(channel).id_drive[20] = 3;
+  BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache
+  BX_SELECTED_DRIVE(channel).id_drive[22] = 4;
+
+  char* firmware = "8FT054  ";
+  for (i = 0; i < strlen(firmware)/2; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[23+i] = (firmware[i*2] << 8) |
+             firmware[i*2 + 1];
+  }
+  BX_ASSERT((23+i) == 27);
+
+  char* model = "Conner Peripherals 540MB - CFA540A      ";
+  for (i = 0; i < strlen(model)/2; i++) {
+       BX_SELECTED_DRIVE(channel).id_drive[27+i] = (model[i*2] << 8) |
+             model[i*2 + 1];
+  }
+  BX_ASSERT((27+i) == 47);
+
+  BX_SELECTED_DRIVE(channel).id_drive[47] = 0x8080; // multiple mode identification
+  BX_SELECTED_DRIVE(channel).id_drive[48] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[49] = 0x0f01;
+
+  BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[51] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[52] = 0x0002;
+  BX_SELECTED_DRIVE(channel).id_drive[53] = 0x0003;
+  BX_SELECTED_DRIVE(channel).id_drive[54] = 0x0418;
+
+  BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+  BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+  BX_SELECTED_DRIVE(channel).id_drive[57] = 0x1e80;
+  BX_SELECTED_DRIVE(channel).id_drive[58] = 0x0010;
+  BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0100 | BX_SELECTED_CONTROLLER(channel).sectors_per_block;
+  BX_SELECTED_DRIVE(channel).id_drive[60] = 0x20e0;
+  BX_SELECTED_DRIVE(channel).id_drive[61] = 0x0010;
+
+  BX_SELECTED_DRIVE(channel).id_drive[62] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0103; // variable (DMA stuff)
+  BX_SELECTED_DRIVE(channel).id_drive[64] = 0x0001; // PIO
+  BX_SELECTED_DRIVE(channel).id_drive[65] = 0x00b4;
+  BX_SELECTED_DRIVE(channel).id_drive[66] = 0x00b4;
+  BX_SELECTED_DRIVE(channel).id_drive[67] = 0x012c;
+  BX_SELECTED_DRIVE(channel).id_drive[68] = 0x00b4;
+
+  for (i = 69; i <= 79; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[80] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[82] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[83] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[84] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[85] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[87] = 0;
+
+  for (i = 88; i <= 127; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[128] = 0x0418;
+  BX_SELECTED_DRIVE(channel).id_drive[129] = 0x103f;
+  BX_SELECTED_DRIVE(channel).id_drive[130] = 0x0418;
+  BX_SELECTED_DRIVE(channel).id_drive[131] = 0x103f;
+  BX_SELECTED_DRIVE(channel).id_drive[132] = 0x0004;
+  BX_SELECTED_DRIVE(channel).id_drive[133] = 0xffff;
+  BX_SELECTED_DRIVE(channel).id_drive[134] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[135] = 0x5050;
+
+  for (i = 136; i <= 144; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  BX_SELECTED_DRIVE(channel).id_drive[145] = 0x302e;
+  BX_SELECTED_DRIVE(channel).id_drive[146] = 0x3245;
+  BX_SELECTED_DRIVE(channel).id_drive[147] = 0x2020;
+  BX_SELECTED_DRIVE(channel).id_drive[148] = 0x2020;
+
+  for (i = 149; i <= 255; i++)
+       BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+#else
+
+  // Identify Drive command return values definition
+  //
+  // This code is rehashed from some that was donated.
+  // I'm using ANSI X3.221-1994, AT Attachment Interface for Disk Drives
+  // and X3T10 2008D Working Draft for ATA-3
+
+
+  // Word 0: general config bit-significant info
+  //   Note: bits 1-5 and 8-14 are now "Vendor specific (obsolete)"
+  //   bit 15: 0=ATA device
+  //           1=ATAPI device
+  //   bit 14: 1=format speed tolerance gap required
+  //   bit 13: 1=track offset option available
+  //   bit 12: 1=data strobe offset option available
+  //   bit 11: 1=rotational speed tolerance is > 0,5% (typo?)
+  //   bit 10: 1=disk transfer rate > 10Mbs
+  //   bit  9: 1=disk transfer rate > 5Mbs but <= 10Mbs
+  //   bit  8: 1=disk transfer rate <= 5Mbs
+  //   bit  7: 1=removable cartridge drive
+  //   bit  6: 1=fixed drive
+  //   bit  5: 1=spindle motor control option implemented
+  //   bit  4: 1=head switch time > 15 usec
+  //   bit  3: 1=not MFM encoded
+  //   bit  2: 1=soft sectored
+  //   bit  1: 1=hard sectored
+  //   bit  0: 0=reserved
+  BX_SELECTED_DRIVE(channel).id_drive[0] = 0x0040;
+
+  // Word 1: number of user-addressable cylinders in
+  //   default translation mode.  If the value in words 60-61
+  //   exceed 16,515,072, this word shall contain 16,383.
+  BX_SELECTED_DRIVE(channel).id_drive[1] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders;
+
+  // Word 2: reserved
+  BX_SELECTED_DRIVE(channel).id_drive[2] = 0;
+
+  // Word 3: number of user-addressable heads in default
+  //   translation mode
+  BX_SELECTED_DRIVE(channel).id_drive[3] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+
+  // Word 4: # unformatted bytes per translated track in default xlate mode
+  // Word 5: # unformatted bytes per sector in default xlated mode
+  // Word 6: # user-addressable sectors per track in default xlate mode
+  // Note: words 4,5 are now "Vendor specific (obsolete)"
+  BX_SELECTED_DRIVE(channel).id_drive[4] = (512 * BX_SELECTED_DRIVE(channel).hard_drive->sectors);
+  BX_SELECTED_DRIVE(channel).id_drive[5] = 512;
+  BX_SELECTED_DRIVE(channel).id_drive[6] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+  // Word 7-9: Vendor specific
+  for (i=7; i<=9; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 10-19: Serial number (20 ASCII characters, 0000h=not specified)
+  // This field is right justified and padded with spaces (20h).
+  for (i=10; i<=19; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 20: buffer type
+  //          0000h = not specified
+  //          0001h = single ported single sector buffer which is
+  //                  not capable of simulataneous data xfers to/from
+  //                  the host and the disk.
+  //          0002h = dual ported multi-sector buffer capable of
+  //                  simulatenous data xfers to/from the host and disk.
+  //          0003h = dual ported mutli-sector buffer capable of
+  //                  simulatenous data xfers with a read caching
+  //                  capability.
+  //          0004h-ffffh = reserved
+  BX_SELECTED_DRIVE(channel).id_drive[20] = 3;
+
+  // Word 21: buffer size in 512 byte increments, 0000h = not specified
+  BX_SELECTED_DRIVE(channel).id_drive[21] = 512; // 512 Sectors = 256kB cache
+
+  // Word 22: # of ECC bytes available on read/write long cmds
+  //          0000h = not specified
+  BX_SELECTED_DRIVE(channel).id_drive[22] = 4;
+
+  // Word 23..26: Firmware revision (8 ascii chars, 0000h=not specified)
+  // This field is left justified and padded with spaces (20h)
+  for (i=23; i<=26; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 27..46: Model number (40 ascii chars, 0000h=not specified)
+  // This field is left justified and padded with spaces (20h)
+//  for (i=27; i<=46; i++)
+//    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+  for (i=0; i<20; i++) {
+    BX_SELECTED_DRIVE(channel).id_drive[27+i] = (BX_SELECTED_MODEL(channel)[i*2] << 8) |
+                                  BX_SELECTED_MODEL(channel)[i*2 + 1];
+    }
+
+  // Word 47: 15-8 Vendor unique
+  //           7-0 00h= read/write multiple commands not implemented
+  //               xxh= maximum # of sectors that can be transferred
+  //                    per interrupt on read and write multiple commands
+  BX_SELECTED_DRIVE(channel).id_drive[47] = max_multiple_sectors;
+
+  // Word 48: 0000h = cannot perform dword IO
+  //          0001h = can    perform dword IO
+  BX_SELECTED_DRIVE(channel).id_drive[48] = 1;
+
+  // Word 49: Capabilities
+  //   15-10: 0 = reserved
+  //       9: 1 = LBA supported
+  //       8: 1 = DMA supported
+  //     7-0: Vendor unique
+  BX_SELECTED_DRIVE(channel).id_drive[49] = 1<<9;
+
+  // Word 50: Reserved
+  BX_SELECTED_DRIVE(channel).id_drive[50] = 0;
+
+  // Word 51: 15-8 PIO data transfer cycle timing mode
+  //           7-0 Vendor unique
+  BX_SELECTED_DRIVE(channel).id_drive[51] = 0x200;
+
+  // Word 52: 15-8 DMA data transfer cycle timing mode
+  //           7-0 Vendor unique
+  BX_SELECTED_DRIVE(channel).id_drive[52] = 0x200;
+
+  // Word 53: 15-1 Reserved
+  //             0 1=the fields reported in words 54-58 are valid
+  //               0=the fields reported in words 54-58 may be valid
+  BX_SELECTED_DRIVE(channel).id_drive[53] = 0;
+
+  // Word 54: # of user-addressable cylinders in curr xlate mode
+  // Word 55: # of user-addressable heads in curr xlate mode
+  // Word 56: # of user-addressable sectors/track in curr xlate mode
+  BX_SELECTED_DRIVE(channel).id_drive[54] = BX_SELECTED_DRIVE(channel).hard_drive->cylinders;
+  BX_SELECTED_DRIVE(channel).id_drive[55] = BX_SELECTED_DRIVE(channel).hard_drive->heads;
+  BX_SELECTED_DRIVE(channel).id_drive[56] = BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+
+  // Word 57-58: Current capacity in sectors
+  // Excludes all sectors used for device specific purposes.
+  temp32 = 
+    BX_SELECTED_DRIVE(channel).hard_drive->cylinders *
+    BX_SELECTED_DRIVE(channel).hard_drive->heads *
+    BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+  BX_SELECTED_DRIVE(channel).id_drive[57] = (temp32 & 0xffff); // LSW
+  BX_SELECTED_DRIVE(channel).id_drive[58] = (temp32 >> 16);    // MSW
+
+  // Word 59: 15-9 Reserved
+  //             8 1=multiple sector setting is valid
+  //           7-0 current setting for number of sectors that can be
+  //               transferred per interrupt on R/W multiple commands
+  BX_SELECTED_DRIVE(channel).id_drive[59] = 0x0000 | curr_multiple_sectors;
+
+  // Word 60-61:
+  // If drive supports LBA Mode, these words reflect total # of user
+  // addressable sectors.  This value does not depend on the current
+  // drive geometry.  If the drive does not support LBA mode, these
+  // words shall be set to 0.
+  Bit32u num_sects = BX_SELECTED_DRIVE(channel).hard_drive->cylinders * BX_SELECTED_DRIVE(channel).hard_drive->heads * BX_SELECTED_DRIVE(channel).hard_drive->sectors;
+  BX_SELECTED_DRIVE(channel).id_drive[60] = num_sects & 0xffff; // LSW
+  BX_SELECTED_DRIVE(channel).id_drive[61] = num_sects >> 16; // MSW
+
+  // Word 62: 15-8 single word DMA transfer mode active
+  //           7-0 single word DMA transfer modes supported
+  // The low order byte identifies by bit, all the Modes which are
+  // supported e.g., if Mode 0 is supported bit 0 is set.
+  // The high order byte contains a single bit set to indiciate
+  // which mode is active.
+  BX_SELECTED_DRIVE(channel).id_drive[62] = 0x0;
+
+  // Word 63: 15-8 multiword DMA transfer mode active
+  //           7-0 multiword DMA transfer modes supported
+  // The low order byte identifies by bit, all the Modes which are
+  // supported e.g., if Mode 0 is supported bit 0 is set.
+  // The high order byte contains a single bit set to indiciate
+  // which mode is active.
+  BX_SELECTED_DRIVE(channel).id_drive[63] = 0x0;
+
+  // Word 64-79 Reserved
+  for (i=64; i<=79; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 80: 15-5 reserved
+  //             4 supports ATA/ATAPI-4
+  //             3 supports ATA-3
+  //             2 supports ATA-2
+  //             1 supports ATA-1
+  //             0 reserved
+  BX_SELECTED_DRIVE(channel).id_drive[80] = (1 << 2) | (1 << 1);
+
+  // Word 81: Minor version number
+  BX_SELECTED_DRIVE(channel).id_drive[81] = 0;
+
+  // Word 82: 15 obsolete
+  //          14 NOP command supported
+  //          13 READ BUFFER command supported
+  //          12 WRITE BUFFER command supported
+  //          11 obsolete
+  //          10 Host protected area feature set supported
+  //           9 DEVICE RESET command supported
+  //           8 SERVICE interrupt supported
+  //           7 release interrupt supported
+  //           6 look-ahead supported
+  //           5 write cache supported
+  //           4 supports PACKET command feature set
+  //           3 supports power management feature set
+  //           2 supports removable media feature set
+  //           1 supports securite mode feature set
+  //           0 support SMART feature set
+  BX_SELECTED_DRIVE(channel).id_drive[82] = 1 << 14;
+  BX_SELECTED_DRIVE(channel).id_drive[83] = 1 << 14;
+  BX_SELECTED_DRIVE(channel).id_drive[84] = 1 << 14;
+  BX_SELECTED_DRIVE(channel).id_drive[85] = 1 << 14;
+  BX_SELECTED_DRIVE(channel).id_drive[86] = 0;
+  BX_SELECTED_DRIVE(channel).id_drive[87] = 1 << 14;
+
+  for (i=88; i<=127; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 128-159 Vendor unique
+  for (i=128; i<=159; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+  // Word 160-255 Reserved
+  for (i=160; i<=255; i++)
+    BX_SELECTED_DRIVE(channel).id_drive[i] = 0;
+
+#endif
+
+  BX_DEBUG(("Drive ID Info. initialized : %04d {%s}", 512, BX_SELECTED_TYPE_STRING(channel)));
+
+  // now convert the id_drive array (native 256 word format) to
+  // the controller buffer (512 bytes)
+  for (i=0; i<=255; i++) {
+    temp16 = BX_SELECTED_DRIVE(channel).id_drive[i];
+    BX_SELECTED_CONTROLLER(channel).buffer[i*2] = temp16 & 0x00ff;
+    BX_SELECTED_CONTROLLER(channel).buffer[i*2+1] = temp16 >> 8;
+    }
+}
+
+  void BX_CPP_AttrRegparmN(3)
+bx_hard_drive_c::init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bool lazy)
+{
+      // BX_SELECTED_CONTROLLER(channel).byte_count is a union of BX_SELECTED_CONTROLLER(channel).cylinder_no;
+      // lazy is used to force a data read in the buffer at the next read.
+
+      if (BX_SELECTED_CONTROLLER(channel).byte_count == 0xffff)
+        BX_SELECTED_CONTROLLER(channel).byte_count = 0xfffe;
+
+      if ((BX_SELECTED_CONTROLLER(channel).byte_count & 1)
+          && !(alloc_length <= BX_SELECTED_CONTROLLER(channel).byte_count)) {
+        BX_INFO(("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x", 
+               BX_SELECTED_CONTROLLER(channel).byte_count, command, BX_SELECTED_CONTROLLER(channel).byte_count - 1));
+        BX_SELECTED_CONTROLLER(channel).byte_count -= 1;
+      }
+
+      if (BX_SELECTED_CONTROLLER(channel).byte_count == 0)
+           BX_PANIC(("ATAPI command with zero byte count"));
+
+      if (alloc_length < 0)
+           BX_PANIC(("Allocation length < 0"));
+      if (alloc_length == 0)
+           alloc_length = BX_SELECTED_CONTROLLER(channel).byte_count;
+
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 0;
+      BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+      BX_SELECTED_CONTROLLER(channel).status.drq = 1;
+      BX_SELECTED_CONTROLLER(channel).status.err = 0;
+
+      // no bytes transfered yet
+      if (lazy)
+           BX_SELECTED_CONTROLLER(channel).buffer_index = 2048;
+      else
+           BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+      BX_SELECTED_CONTROLLER(channel).drq_index = 0;
+
+      if (BX_SELECTED_CONTROLLER(channel).byte_count > req_length)
+           BX_SELECTED_CONTROLLER(channel).byte_count = req_length;
+
+      if (BX_SELECTED_CONTROLLER(channel).byte_count > alloc_length)
+           BX_SELECTED_CONTROLLER(channel).byte_count = alloc_length;
+
+      BX_SELECTED_DRIVE(channel).atapi.command = command;
+      BX_SELECTED_DRIVE(channel).atapi.drq_bytes = BX_SELECTED_CONTROLLER(channel).byte_count;
+      BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining = (req_length < alloc_length) ? req_length : alloc_length;
+
+      // if (lazy) {
+           // // bias drq_bytes and total_bytes_remaining
+           // BX_SELECTED_DRIVE(channel).atapi.drq_bytes += 2048;
+           // BX_SELECTED_DRIVE(channel).atapi.total_bytes_remaining += 2048;
+      // }
+}
+
+void
+bx_hard_drive_c::atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc)
+{
+      BX_ERROR(("atapi_cmd_error channel=%02x key=%02x asc=%02x", channel, sense_key, asc));
+
+      BX_SELECTED_CONTROLLER(channel).error_register = sense_key << 4;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+      BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+      BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+      BX_SELECTED_CONTROLLER(channel).status.write_fault = 0;
+      BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+      BX_SELECTED_CONTROLLER(channel).status.err = 1;
+
+      BX_SELECTED_DRIVE(channel).sense.sense_key = sense_key;
+      BX_SELECTED_DRIVE(channel).sense.asc = asc;
+      BX_SELECTED_DRIVE(channel).sense.ascq = 0;
+}
+
+void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::atapi_cmd_nop(Bit8u channel)
+{
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.i_o = 1;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.c_d = 1;
+      BX_SELECTED_CONTROLLER(channel).interrupt_reason.rel = 0;
+      BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+      BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+      BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+      BX_SELECTED_CONTROLLER(channel).status.err = 0;
+}
+
+void
+bx_hard_drive_c::init_mode_sense_single(Bit8u channel, const void* src, int size)
+{
+      // Header
+      BX_SELECTED_CONTROLLER(channel).buffer[0] = (size+6) >> 8;
+      BX_SELECTED_CONTROLLER(channel).buffer[1] = (size+6) & 0xff;
+      BX_SELECTED_CONTROLLER(channel).buffer[2] = 0x70; // no media present
+      BX_SELECTED_CONTROLLER(channel).buffer[3] = 0; // reserved
+      BX_SELECTED_CONTROLLER(channel).buffer[4] = 0; // reserved
+      BX_SELECTED_CONTROLLER(channel).buffer[5] = 0; // reserved
+      BX_SELECTED_CONTROLLER(channel).buffer[6] = 0; // reserved
+      BX_SELECTED_CONTROLLER(channel).buffer[7] = 0; // reserved
+
+      // Data
+      memcpy(BX_SELECTED_CONTROLLER(channel).buffer + 8, src, size);
+}
+
+  void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::ready_to_send_atapi(Bit8u channel)
+{
+      raise_interrupt(channel);
+}
+
+void BX_CPP_AttrRegparmN(1)
+bx_hard_drive_c::raise_interrupt(Bit8u channel)
+{
+       BX_DEBUG(("raise_interrupt called, disable_irq = %02x", BX_SELECTED_CONTROLLER(channel).control.disable_irq));
+       if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) { BX_DEBUG(("raising interrupt")); } else { BX_DEBUG(("Not raising interrupt")); }
+      if (!BX_SELECTED_CONTROLLER(channel).control.disable_irq) {
+          Bit32u irq = BX_HD_THIS channels[channel].irq; 
+          BX_DEBUG(("Raising interrupt %d {%s}", irq, BX_SELECTED_TYPE_STRING(channel)));
+          DEV_pic_raise_irq(irq);
+      } else {
+          if (bx_dbg.disk || (BX_SELECTED_IS_CD(channel) && bx_dbg.cdrom))
+              BX_INFO(("Interrupt masked {%s}", BX_SELECTED_TYPE_STRING(channel)));
+      }
+}
+
+  void
+bx_hard_drive_c::command_aborted(Bit8u channel, unsigned value)
+{
+  BX_DEBUG(("aborting on command 0x%02x {%s}", value, BX_SELECTED_TYPE_STRING(channel)));
+  BX_SELECTED_CONTROLLER(channel).current_command = 0;
+  BX_SELECTED_CONTROLLER(channel).status.busy = 0;
+  BX_SELECTED_CONTROLLER(channel).status.drive_ready = 1;
+  BX_SELECTED_CONTROLLER(channel).status.err = 1;
+  BX_SELECTED_CONTROLLER(channel).error_register = 0x04; // command ABORTED
+  BX_SELECTED_CONTROLLER(channel).status.drq = 0;
+  BX_SELECTED_CONTROLLER(channel).status.seek_complete = 0;
+  BX_SELECTED_CONTROLLER(channel).status.corrected_data = 0;
+  BX_SELECTED_CONTROLLER(channel).buffer_index = 0;
+  raise_interrupt(channel);
+}
+
+  Bit32u
+bx_hard_drive_c::get_device_handle(Bit8u channel, Bit8u device)
+{
+  BX_DEBUG(("get_device_handle %d %d",channel, device));
+  if ((channel < BX_MAX_ATA_CHANNEL) && (device < 2)) {
+    return ((channel*2) + device);
+    }
+  
+  return BX_MAX_ATA_CHANNEL*2;
+}
+
+  Bit32u
+bx_hard_drive_c::get_first_cd_handle(void)
+{
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    if (BX_DRIVE_IS_CD(channel,0)) return (channel*2);
+    if (BX_DRIVE_IS_CD(channel,1)) return ((channel*2) + 1);
+    }
+  return BX_MAX_ATA_CHANNEL*2;
+}
+
+  unsigned
+bx_hard_drive_c::get_cd_media_status(Bit32u handle)
+{
+  if ( handle >= BX_MAX_ATA_CHANNEL*2 ) return 0;
+
+  Bit8u channel = handle / 2;
+  Bit8u device  = handle % 2;
+  return( BX_HD_THIS channels[channel].drives[device].cdrom.ready );
+}
+
+  unsigned
+bx_hard_drive_c::set_cd_media_status(Bit32u handle, unsigned status)
+{
+  BX_DEBUG (("set_cd_media_status handle=%d status=%d", handle, status));
+  if ( handle >= BX_MAX_ATA_CHANNEL*2 ) return 0;
+
+  Bit8u channel = handle / 2;
+  Bit8u device  = handle % 2;
+
+  // if setting to the current value, nothing to do
+  if (status == BX_HD_THIS channels[channel].drives[device].cdrom.ready)
+    return(status);
+  // return 0 if no cdromd is present
+  if (!BX_DRIVE_IS_CD(channel,device))
+    return(0);
+
+  if (status == 0) {
+    // eject cdrom if not locked by guest OS
+    if (BX_HD_THIS channels[channel].drives[device].cdrom.locked) return(1);
+    else {
+#ifdef LOWLEVEL_CDROM
+      BX_HD_THIS channels[channel].drives[device].cdrom.cd->eject_cdrom();
+#endif
+      BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+      bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+      }
+    }
+  else {
+    // insert cdrom
+#ifdef LOWLEVEL_CDROM
+    if (BX_HD_THIS channels[channel].drives[device].cdrom.cd->insert_cdrom(bx_options.atadevice[channel][device].Opath->getptr())) {
+      BX_INFO(( "Media present in CD-ROM drive"));
+      BX_HD_THIS channels[channel].drives[device].cdrom.ready = 1;
+      BX_HD_THIS channels[channel].drives[device].cdrom.capacity = BX_HD_THIS channels[channel].drives[device].cdrom.cd->capacity();
+      bx_options.atadevice[channel][device].Ostatus->set(BX_INSERTED);
+      BX_SELECTED_DRIVE(channel).sense.sense_key = SENSE_UNIT_ATTENTION;
+      BX_SELECTED_DRIVE(channel).sense.asc = 0;
+      BX_SELECTED_DRIVE(channel).sense.ascq = 0;
+      raise_interrupt(channel);
+      }
+    else {                 
+#endif
+      BX_INFO(( "Could not locate CD-ROM, continuing with media not present"));
+      BX_HD_THIS channels[channel].drives[device].cdrom.ready = 0;
+      bx_options.atadevice[channel][device].Ostatus->set(BX_EJECTED);
+#ifdef LOWLEVEL_CDROM
+      }
+#endif
+    }
+  return( BX_HD_THIS channels[channel].drives[device].cdrom.ready );
+}
+
+
+/*** default_image_t function definitions ***/
+
+int default_image_t::open (const char* pathname)
+{
+      return open(pathname, O_RDWR);
+}
+
+int default_image_t::open (const char* pathname, int flags)
+{
+      fd = ::open(pathname, flags
+#ifdef O_BINARY
+                 | O_BINARY
+#endif
+           );
+
+      if (fd < 0) {
+           return fd;
+      }
+
+      /* look at size of image file to calculate disk geometry */
+      struct stat stat_buf;
+      int ret = fstat(fd, &stat_buf);
+      if (ret) {
+           BX_PANIC(("fstat() returns error!"));
+      }
+
+      return fd;
+}
+
+void default_image_t::close ()
+{
+      if (fd > -1) {
+           ::close(fd);
+      }
+}
+
+off_t default_image_t::lseek (off_t offset, int whence)
+{
+      return ::lseek(fd, offset, whence);
+}
+
+ssize_t default_image_t::read (void* buf, size_t count)
+{
+      return ::read(fd, (char*) buf, count);
+}
+
+ssize_t default_image_t::write (const void* buf, size_t count)
+{
+      return ::write(fd, (char*) buf, count);
+}
+
+char increment_string (char *str, int diff)
+{
+  // find the last character of the string, and increment it.
+  char *p = str;
+  while (*p != 0) p++;
+  BX_ASSERT (p>str);  // choke on zero length strings
+  p--;  // point to last character of the string
+  (*p) += diff;  // increment to next/previous ascii code.
+  BX_DEBUG(("increment string returning '%s'", str));
+ return (*p);
+}
+
+/*** concat_image_t function definitions ***/
+
+concat_image_t::concat_image_t ()
+{
+  fd = -1;
+}
+
+void concat_image_t::increment_string (char *str)
+{
+ ::increment_string(str, +1);
+}
+
+int concat_image_t::open (const char* pathname0)
+{
+  char *pathname = strdup (pathname0);
+  BX_DEBUG(("concat_image_t.open"));
+  off_t start_offset = 0;
+  for (int i=0; i<BX_CONCAT_MAX_IMAGES; i++) {
+    fd_table[i] = ::open(pathname, O_RDWR
+#ifdef O_BINARY
+               | O_BINARY
+#endif
+         );
+    if (fd_table[i] < 0) {
+      // open failed.
+      // if no FD was opened successfully, return -1 (fail).
+      if (i==0) return -1;
+      // otherwise, it only means that all images in the series have 
+      // been opened.  Record the number of fds opened successfully.
+      maxfd = i; 
+      break;
+    }
+    BX_DEBUG(("concat_image: open image %s, fd[%d] = %d", pathname, i, fd_table[i]));
+    /* look at size of image file to calculate disk geometry */
+    struct stat stat_buf;
+    int ret = fstat(fd_table[i], &stat_buf);
+    if (ret) {
+         BX_PANIC(("fstat() returns error!"));
+    }
+#ifdef S_ISBLK
+    if (S_ISBLK(stat_buf.st_mode)) {
+      BX_PANIC(("block devices should REALLY NOT be used with --enable-split-hd. "
+                "Please reconfigure with --disable-split-hd"));
+    }
+#endif
+    if ((stat_buf.st_size % 512) != 0) {
+      BX_PANIC(("size of disk image must be multiple of 512 bytes"));
+    }
+    length_table[i] = stat_buf.st_size;
+    start_offset_table[i] = start_offset;
+    start_offset += stat_buf.st_size;
+    increment_string (pathname);
+  }
+  // start up with first image selected
+  index = 0;
+  fd = fd_table[0];
+  thismin = 0;
+  thismax = length_table[0]-1;
+  seek_was_last_op = 0;
+  return 0; // success.
+}
+
+void concat_image_t::close ()
+{
+  BX_DEBUG(("concat_image_t.close"));
+  if (fd > -1) {
+    ::close(fd);
+  }
+}
+
+off_t concat_image_t::lseek (off_t offset, int whence)
+{
+  if ((offset % 512) != 0) 
+    BX_PANIC( ("lseek HD with offset not multiple of 512"));
+  BX_DEBUG(("concat_image_t.lseek(%d)", whence));
+  // is this offset in this disk image?
+  if (offset < thismin) {
+    // no, look at previous images
+    for (int i=index-1; i>=0; i--) {
+      if (offset >= start_offset_table[i]) {
+       index = i;
+       fd = fd_table[i];
+       thismin = start_offset_table[i];
+       thismax = thismin + length_table[i] - 1;
+       BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
+       break;
+      }
+    }
+  } else if (offset > thismax) {
+    // no, look at later images
+    for (int i=index+1; i<maxfd; i++) {
+      if (offset < start_offset_table[i] + length_table[i]) {
+       index = i;
+       fd = fd_table[i];
+       thismin = start_offset_table[i];
+       thismax = thismin + length_table[i] - 1;
+       BX_DEBUG(("concat_image_t.lseek to earlier image, index=%d", index));
+       break;
+      }
+    }
+  }
+  // now offset should be within the current image.
+  offset -= start_offset_table[index];
+  if (offset < 0 || offset >= length_table[index]) {
+    BX_PANIC(("concat_image_t.lseek to byte %ld failed", (long)offset));
+    return -1;
+  }
+
+  seek_was_last_op = 1;
+  return ::lseek(fd, offset, whence);
+}
+
+ssize_t concat_image_t::read (void* buf, size_t count)
+{
+  if (bx_dbg.disk)
+    BX_DEBUG(("concat_image_t.read %ld bytes", (long)count));
+  // notice if anyone does sequential read or write without seek in between.
+  // This can be supported pretty easily, but needs additional checks for
+  // end of a partial image.
+  if (!seek_was_last_op)
+    BX_PANIC( ("no seek before read"));
+  return ::read(fd, (char*) buf, count);
+}
+
+ssize_t concat_image_t::write (const void* buf, size_t count)
+{
+  BX_DEBUG(("concat_image_t.write %ld bytes", (long)count));
+  // notice if anyone does sequential read or write without seek in between.
+  // This can be supported pretty easily, but needs additional checks for
+  // end of a partial image.
+  if (!seek_was_last_op)
+    BX_PANIC( ("no seek before write"));
+  return ::write(fd, (char*) buf, count);
+}
+
+/*** sparse_image_t function definitions ***/
+sparse_image_t::sparse_image_t ()
+{
+  fd = -1;
+  pathname = NULL;
+#ifdef _POSIX_MAPPED_FILES
+ mmap_header = NULL;
+#endif
+ pagetable = NULL;
+}
+
+
+/*
+void showpagetable(uint32 * pagetable, size_t numpages)
+{
+ printf("Non null pages: ");
+ for (int i = 0; i < numpages; i++)
+ {
+   if (pagetable[i] != 0xffffffff)
+   {
+     printf("%d ", i);
+   }
+ }
+ printf("\n");
+}
+*/
+
+
+void sparse_image_t::read_header()
+{
+ BX_ASSERT(sizeof(header) == SPARSE_HEADER_SIZE);
+
+ int ret = ::read(fd, &header, sizeof(header));
+
+ if (-1 == ret)
+ {
+     panic(strerror(errno));
+ }
+
+ if (sizeof(header) != ret)
+ {
+   panic("could not read entire header");
+ }
+
+ if (dtoh32(header.magic) != SPARSE_HEADER_MAGIC)
+ {
+   panic("failed header magic check");
+ }
+
+ if (dtoh32(header.version) != 1)
+ {
+   panic("unknown version in header");
+ }
+
+ pagesize = dtoh32(header.pagesize);
+ uint32 numpages = dtoh32(header.numpages);
+
+ total_size = pagesize;
+ total_size *= numpages;
+
+ pagesize_shift = 0;
+ while ((pagesize >> pagesize_shift) > 1) pagesize_shift++;
+
+ if ((uint32)(1 << pagesize_shift) != pagesize)
+ {
+   panic("failed block size header check");
+ }
+
+ pagesize_mask = pagesize - 1;
+
+ size_t  preamble_size = (sizeof(uint32) * numpages) + sizeof(header);
+ data_start = 0;
+ while (data_start < preamble_size) data_start += pagesize;
+
+ bool did_mmap = false;
+
+#ifdef _POSIX_MAPPED_FILES
+// Try to memory map from the beginning of the file (0 is trivially a page multiple)
+ void * mmap_header = mmap(NULL, preamble_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mmap_header == MAP_FAILED)
+ {
+   BX_INFO(("failed to mmap sparse disk file - using conventional file access"));
+   mmap_header = NULL;
+ }
+ else
+ {
+   mmap_length = preamble_size;
+   did_mmap = true;
+   pagetable = ((uint32 *) (((uint8 *) mmap_header) + sizeof(header)));
+
+//   system_pagesize = getpagesize();
+   system_pagesize_mask = getpagesize() - 1;
+ }
+#endif
+
+ if (!did_mmap)
+ {
+   pagetable = new uint32[numpages];
+
+   if (pagetable == NULL)
+   {
+     panic("could not allocate memory for sparse disk block table");
+   }
+
+   ret = ::read(fd, pagetable, sizeof(uint32) * numpages);
+
+   if (-1 == ret)
+   {
+       panic(strerror(errno));
+   }
+
+   if ((int)(sizeof(uint32) * numpages) != ret)
+   {
+     panic("could not read entire block table");
+   }
+ }
+}
+
+int sparse_image_t::open (const char* pathname0)
+{
+ pathname = strdup(pathname0);
+ BX_DEBUG(("sparse_image_t.open"));
+
+ fd = ::open(pathname, O_RDWR
+#ifdef O_BINARY
+   | O_BINARY
+#endif
+   );
+
+ if (fd < 0)
+ {
+   // open failed.
+   return -1;
+ }
+ BX_DEBUG(("sparse_image: open image %s", pathname));
+
+ read_header();
+
+ struct stat stat_buf;
+ if (0 != fstat(fd, &stat_buf)) panic(("fstat() returns error!"));
+
+ underlying_filesize = stat_buf.st_size;
+
+ if ((underlying_filesize % pagesize) != 0)
+   panic("size of sparse disk image is not multiple of page size");
+
+ underlying_current_filepos = 0;
+ if (-1 == ::lseek(fd, 0, SEEK_SET))
+   panic("error while seeking to start of file");
+
+ lseek(0, SEEK_SET);
+
+ //showpagetable(pagetable, header.numpages);
+
+ char * parentpathname = strdup(pathname);
+ char lastchar = ::increment_string(parentpathname, -1);
+
+ if ((lastchar >= '0') && (lastchar <= '9'))
+ {
+   struct stat stat_buf;
+   if (0 == stat(parentpathname, &stat_buf))
+   {
+     parent_image = new sparse_image_t();
+     int ret = parent_image->open(parentpathname);
+     if (ret != 0) return ret;
+     if (    (parent_image->pagesize != pagesize)
+         ||  (parent_image->total_size != total_size))
+     {
+       panic("child drive image does not have same page count/page size configuration");
+     }
+   }
+ }
+
+ if (parentpathname != NULL) free(parentpathname);
+
+ return 0; // success.
+}
+
+void sparse_image_t::close ()
+{
+  BX_DEBUG(("concat_image_t.close"));
+  if (pathname != NULL)
+  {
+   free(pathname);
+ }
+#ifdef _POSIX_MAPPED_FILES
+ if (mmap_header != NULL)
+ {
+   int ret = munmap(mmap_header, mmap_length);
+   if (ret != 0)
+     BX_INFO(("failed to un-memory map sparse disk file"));
+ }
+ pagetable = NULL; // We didn't malloc it
+#endif
+  if (fd > -1) {
+    ::close(fd);
+  }
+ if (pagetable != NULL)
+ {
+   delete [] pagetable;
+ }
+ if (parent_image != NULL)
+ {
+   delete parent_image;
+ }
+}
+
+off_t sparse_image_t::lseek (off_t offset, int whence)
+{
+ //showpagetable(pagetable, header.numpages);
+
+ if ((offset % 512) != 0)
+    BX_PANIC( ("lseek HD with offset not multiple of 512"));
+ if (whence != SEEK_SET)
+   BX_PANIC( ("lseek HD with whence not SEEK_SET"));
+
+ BX_DEBUG(("sparse_image_t.lseek(%d)", whence));
+
+ if (offset > total_size)
+ {
+   BX_PANIC(("sparse_image_t.lseek to byte %ld failed", (long)offset));
+    return -1;
+  }
+
+ //printf("Seeking to position %ld\n", (long) offset);
+
+ set_virtual_page(offset >> pagesize_shift);
+ position_page_offset = offset & pagesize_mask;
+
+ return 0;
+}
+
+inline off_t sparse_image_t::get_physical_offset()
+{
+ off_t physical_offset = data_start;
+ physical_offset += (position_physical_page << pagesize_shift);
+ physical_offset += position_page_offset;
+
+ return physical_offset;
+}
+
+inline void sparse_image_t::set_virtual_page(uint32 new_virtual_page)
+{
+ position_virtual_page = new_virtual_page;
+
+ position_physical_page = dtoh32(pagetable[position_virtual_page]);
+}
+
+ssize_t sparse_image_t::read_page_fragment(uint32 read_virtual_page, uint32 read_page_offset, size_t read_size, void * buf)
+{
+ if (read_virtual_page != position_virtual_page)
+ {
+   set_virtual_page(read_virtual_page);
+ }
+
+ position_page_offset = read_page_offset;
+
+ if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
+ {
+   if (parent_image != NULL)
+   {
+     return parent_image->read_page_fragment(read_virtual_page, read_page_offset, read_size, buf);
+   }
+   else
+   {
+     memset(buf, read_size, 0);
+   }
+ }
+ else
+ {
+   off_t physical_offset = get_physical_offset();
+
+   if (physical_offset != underlying_current_filepos)
+   {
+     int ret = ::lseek(fd, physical_offset, SEEK_SET);
+     // underlying_current_filepos update deferred
+     if (ret == -1)
+       panic(strerror(errno));
+   }
+
+   //printf("Reading %s at position %ld size %d\n", pathname, (long) physical_offset, (long) read_size);
+   ssize_t readret = ::read(fd, buf, read_size);
+
+   if (readret == -1)
+   {
+     panic(strerror(errno));
+   }
+
+   if ((size_t)readret != read_size)
+   {
+     panic("could not read block contents from file");
+   }
+
+   underlying_current_filepos = physical_offset + read_size;
+ }
+
+ return read_size;
+}
+
+ssize_t sparse_image_t::read(void* buf, size_t count)
+{
+ //showpagetable(pagetable, header.numpages);
+ ssize_t total_read = 0;
+
+ if (bx_dbg.disk)
+    BX_DEBUG(("sparse_image_t.read %ld bytes", (long)count));
+
+ while (count != 0)
+ {
+   size_t can_read = pagesize - position_page_offset;
+   if (count < can_read) can_read = count;
+
+   BX_ASSERT (can_read != 0);
+
+   size_t  was_read = read_page_fragment(position_virtual_page, position_page_offset, can_read, buf);
+
+   BX_ASSERT(was_read == can_read);
+
+   total_read += can_read;
+
+   position_page_offset += can_read;
+   if (position_page_offset == pagesize)
+   {
+     position_page_offset = 0;
+     set_virtual_page(position_virtual_page + 1);
+   }
+
+   BX_ASSERT(position_page_offset < pagesize);
+
+   buf = (((uint8 *) buf) + can_read);
+   count -= can_read;
+ }
+
+ return total_read;
+}
+
+void sparse_image_t::panic(const char * message)
+{
+ char buffer[1024];
+ if (message == NULL)
+ {
+   snprintf(buffer, sizeof(buffer), "error with sparse disk image %s", pathname);
+ }
+ else
+ {
+   snprintf(buffer, sizeof(buffer), "error with sparse disk image %s - %s", pathname, message);
+ }
+ BX_PANIC((buffer));
+}
+
+ssize_t sparse_image_t::write (const void* buf, size_t count)
+{
+ //showpagetable(pagetable, header.numpages);
+
+ ssize_t total_written = 0;
+
+ uint32  update_pagetable_start = position_virtual_page;
+ uint32  update_pagetable_count = 0;
+
+ if (bx_dbg.disk)
+    BX_DEBUG(("sparse_image_t.write %ld bytes", (long)count));
+
+ while (count != 0)
+ {
+   size_t can_write = pagesize - position_page_offset;
+   if (count < can_write) can_write = count;
+
+   BX_ASSERT (can_write != 0);
+
+   if (position_physical_page == SPARSE_PAGE_NOT_ALLOCATED)
+   {
+     // We just add on another page at the end of the file
+     // Reclamation, compaction etc should currently be done off-line
+
+     size_t  data_size = underlying_filesize - data_start;
+     BX_ASSERT((data_size % pagesize) == 0);
+
+
+     uint32  data_size_pages = data_size / pagesize;
+     uint32  next_data_page = data_size_pages;
+
+     pagetable[position_virtual_page] = htod32(next_data_page);
+     position_physical_page = next_data_page;
+
+     off_t page_file_start = data_start + (position_physical_page << pagesize_shift);
+
+     if (parent_image != NULL)
+     {
+       // If we have a parent, we must merge our portion with the parent
+       void * writebuffer = NULL;
+
+       if (can_write == pagesize)
+       {
+         writebuffer = (void *) buf;
+       }
+       else
+       {
+         writebuffer = malloc(pagesize);
+         if (writebuffer == NULL)
+           panic("Cannot allocate sufficient memory for page-merge in write");
+
+         // Read entire page - could optimize, but simple for now
+         parent_image->read_page_fragment(position_virtual_page, 0, pagesize, writebuffer);
+
+         void * dest_start = ((uint8 *) writebuffer) + position_page_offset;
+         memcpy(dest_start, buf, can_write);
+       }
+
+       int ret;
+       ret = ::lseek(fd, page_file_start, SEEK_SET);
+       // underlying_current_filepos update deferred
+       if (-1 == ret) panic(strerror(errno));
+
+       ret = ::write(fd, writebuffer, pagesize);
+
+       if (-1 == ret) panic(strerror(errno));
+
+       if (pagesize != (uint32)ret) panic("failed to write entire merged page to disk");
+
+       if (can_write != pagesize)
+       {
+         free(writebuffer);
+       }
+     }
+     else
+     {
+       // We need to write a zero page because read has been returning zeroes
+       // We seek as close to the page end as possible, and then write a little
+       // This produces a sparse file which has blanks
+       // Also very quick, even when pagesize is massive
+       int ret;
+       ret = ::lseek(fd, page_file_start + pagesize - 4, SEEK_SET);
+       // underlying_current_filepos update deferred
+       if (-1 == ret) panic(strerror(errno));
+
+       uint32  zero = 0;
+       ret = ::write(fd, &zero, 4);
+
+       if (-1 == ret) panic(strerror(errno));
+
+       if (4 != ret) panic("failed to write entire blank page to disk");
+     }
+
+     update_pagetable_count = (position_virtual_page - update_pagetable_start) + 1;
+     underlying_filesize = underlying_current_filepos = page_file_start + pagesize;
+   }
+
+   BX_ASSERT(position_physical_page != SPARSE_PAGE_NOT_ALLOCATED);
+
+   off_t physical_offset = get_physical_offset();
+
+   if (physical_offset != underlying_current_filepos)
+   {
+     int ret = ::lseek(fd, physical_offset, SEEK_SET);
+     // underlying_current_filepos update deferred
+     if (ret == -1)
+       panic(strerror(errno));
+   }
+
+   //printf("Writing at position %ld size %d\n", (long) physical_offset, can_write);
+   ssize_t writeret = ::write(fd, buf, can_write);
+
+   if (writeret == -1)
+   {
+     panic(strerror(errno));
+   }
+
+   if ((size_t)writeret != can_write)
+   {
+     panic("could not write block contents to file");
+   }
+
+   underlying_current_filepos = physical_offset + can_write;
+
+   total_written += can_write;
+
+   position_page_offset += can_write;
+   if (position_page_offset == pagesize)
+   {
+     position_page_offset = 0;
+     set_virtual_page(position_virtual_page + 1);
+   }
+
+   BX_ASSERT(position_page_offset < pagesize);
+
+   buf = (((uint8 *) buf) + can_write);
+   count -= can_write;
+ }
+
+ if (update_pagetable_count != 0)
+ {
+   bool done = false;
+   off_t pagetable_write_from = sizeof(header) + (sizeof(uint32) * update_pagetable_start);
+   size_t  write_bytecount = update_pagetable_count * sizeof(uint32);
+
+#ifdef _POSIX_MAPPED_FILES
+   if (mmap_header != NULL)
+   {
+     // Sync from the beginning of the page
+     size_t system_page_offset = pagetable_write_from & system_pagesize_mask;
+     void * start = ((uint8 *) mmap_header + pagetable_write_from - system_page_offset);
+
+     int ret = msync(start, system_page_offset + write_bytecount, MS_ASYNC);
+
+     if (ret != 0)
+       panic(strerror(errno));
+
+     done = true;
+   }
+#endif
+
+   if (!done)
+   {
+     int ret = ::lseek(fd, pagetable_write_from, SEEK_SET);
+     // underlying_current_filepos update deferred
+     if (ret == -1) panic(strerror(errno));
+
+     //printf("Writing header at position %ld size %ld\n", (long) pagetable_write_from, (long) write_bytecount);
+     ret = ::write(fd, &pagetable[update_pagetable_start], write_bytecount);
+     if (ret == -1) panic(strerror(errno));
+     if ((size_t)ret != write_bytecount) panic("could not write entire updated block header");
+
+     underlying_current_filepos = pagetable_write_from + write_bytecount;
+   }
+ }
+
+ return total_written;
+}
+
+#if DLL_HD_SUPPORT
+/*** dll_image_t function definitions ***/
+
+/*
+function vdisk_open(path:PChar;numclusters,clustersize:integer):integer;
+procedure vdisk_read(vunit:integer;blk:integer;var buf:TBlock);
+procedure vdisk_write(vunit:integer;blk:integer;var buf:TBlock);
+procedure vdisk_close(vunit:integer);
+*/
+
+HINSTANCE hlib_vdisk = 0;
+
+int (*vdisk_open)  (const char *path,int numclusters,int clustersize);
+void (*vdisk_read)   (int vunit,int blk,void *buf);
+void (*vdisk_write)  (int vunit,int blk,const void *buf);
+void (*vdisk_close) (int vunit);
+
+int dll_image_t::open (const char* pathname)
+{
+    if (hlib_vdisk == 0) {
+      hlib_vdisk = LoadLibrary("vdisk.dll");
+      if (hlib_vdisk != 0) {
+        vdisk_read = (void (*)(int,int,void*))        GetProcAddress(hlib_vdisk,"vdisk_read");
+        vdisk_write = (void (*)(int,int,const void*)) GetProcAddress(hlib_vdisk,"vdisk_write");
+        vdisk_open = (int (*)(const char *,int,int))  GetProcAddress(hlib_vdisk,"vdisk_open");
+        vdisk_close = (void (*)(int))                 GetProcAddress(hlib_vdisk,"vdisk_close");
+      }
+    }
+    if (hlib_vdisk != 0) {
+      vunit = vdisk_open(pathname,0x10000,64);
+      vblk = 0;
+    } else {
+      vunit = -2;
+    }
+    return vunit;
+}
+
+void dll_image_t::close ()
+{
+   if (vunit >= 0 && hlib_vdisk != 0) {
+     vdisk_close(vunit);
+   }
+}
+
+off_t dll_image_t::lseek (off_t offset, int whence)
+{
+      vblk = offset >> 9;
+      return 0;
+}
+
+ssize_t dll_image_t::read (void* buf, size_t count)
+{
+      if (vunit >= 0 && hlib_vdisk != 0) {
+         vdisk_read(vunit,vblk,buf);
+         return count;
+      } else {
+         return -1;
+      }
+}
+
+ssize_t dll_image_t::write (const void* buf, size_t count)
+{
+      if (vunit >= 0 && hlib_vdisk != 0) {
+        vdisk_write(vunit,vblk,buf);
+        return count;
+      } else {
+         return -1;
+      }
+}
+#endif // DLL_HD_SUPPORT
+
+error_recovery_t::error_recovery_t ()
+{
+      if (sizeof(error_recovery_t) != 8) {
+           BX_PANIC(("error_recovery_t has size != 8"));
+      }
+
+      data[0] = 0x01;
+      data[1] = 0x06;
+      data[2] = 0x00;
+      data[3] = 0x05; // Try to recover 5 times
+      data[4] = 0x00;
+      data[5] = 0x00;
+      data[6] = 0x00;
+      data[7] = 0x00;
+}
+
+uint16  BX_CPP_AttrRegparmN(1) 
+read_16bit(const uint8* buf)
+{
+      return (buf[0] << 8) | buf[1];
+}
+
+uint32  BX_CPP_AttrRegparmN(1)
+read_32bit(const uint8* buf)
+{
+      return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+// redolog implementation
+redolog_t::redolog_t ()
+{
+        fd = -1;
+        catalog = NULL;
+        bitmap = NULL;
+        extent_index = (Bit32u)0;
+        extent_offset = (Bit32u)0;
+        extent_next = (Bit32u)0;
+}
+
+void
+redolog_t::print_header()
+{
+        BX_INFO(("redolog : Standard Header : magic='%s', type='%s', subtype='%s', version = %d.%d",
+                header.standard.magic, header.standard.type, header.standard.subtype,
+                dtoh32(header.standard.version)/0x10000,
+                dtoh32(header.standard.version)%0x10000));
+        BX_INFO(("redolog : Specific Header : #entries=%d, bitmap size=%d, exent size = %d disk size = %lld",
+                dtoh32(header.specific.catalog),
+                dtoh32(header.specific.bitmap),
+                dtoh32(header.specific.extent),
+                dtoh64(header.specific.disk)));
+}
+
+int 
+redolog_t::make_header (const char* type, Bit64u size)
+{
+        Bit32u entries, extent_size, bitmap_size;
+        Bit64u maxsize;
+        Bit32u flip=0;
+
+        // Set standard header values
+        strcpy((char*)header.standard.magic, STANDARD_HEADER_MAGIC);
+        strcpy((char*)header.standard.type, REDOLOG_TYPE);
+        strcpy((char*)header.standard.subtype, type);
+        header.standard.version = htod32(STANDARD_HEADER_VERSION);
+        header.standard.header = htod32(STANDARD_HEADER_SIZE);
+
+        entries = 512;
+        bitmap_size = 1;
+
+        // Compute #entries and extent size values
+        do {
+                extent_size = 8 * bitmap_size * 512;
+
+                header.specific.catalog = htod32(entries);
+                header.specific.bitmap = htod32(bitmap_size);
+                header.specific.extent = htod32(extent_size);
+                
+                maxsize = (Bit64u)entries * (Bit64u)extent_size;
+
+                flip++;
+
+                if(flip&0x01) bitmap_size *= 2;
+                else entries *= 2;
+        } while (maxsize < size);
+
+        header.specific.disk = htod64(size);
+        
+        print_header();
+
+        catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
+        bitmap = (Bit8u*)malloc(dtoh32(header.specific.bitmap));
+
+        if ((catalog == NULL) || (bitmap==NULL))
+                BX_PANIC(("redolog : could not malloc catalog or bitmap"));
+
+        for (Bit32u i=0; i<dtoh32(header.specific.catalog); i++)
+                catalog[i] = htod32(REDOLOG_PAGE_NOT_ALLOCATED);
+
+        bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
+        extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
+
+        BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
+        BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
+
+        return 0;
+}
+
+int 
+redolog_t::create (const char* filename, const char* type, Bit64u size)
+{
+        int filedes;
+
+        BX_INFO(("redolog : creating redolog %s", filename));
+
+        filedes = ::open(filename, O_RDWR | O_CREAT | O_TRUNC
+#ifdef O_BINARY
+            | O_BINARY
+#endif
+              , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
+
+        return create(filedes, type, size);
+}
+
+int 
+redolog_t::create (int filedes, const char* type, Bit64u size)
+{
+        fd = filedes;
+
+        if (fd < 0)
+        {
+                // open failed.
+                return -1;
+        }
+
+        if (make_header(type, size) < 0)
+        {
+                return -1;
+        }
+
+        // Write header
+        ::write(fd, &header, dtoh32(header.standard.header));
+
+        // Write catalog
+        // FIXME could mmap
+        ::write(fd, catalog, dtoh32(header.specific.catalog) * sizeof (Bit32u));
+
+        return 0;
+}
+
+int 
+redolog_t::open (const char* filename, const char *type, Bit64u size)
+{
+        int res;
+
+        fd = ::open(filename, O_RDWR
+#ifdef O_BINARY
+            | O_BINARY
+#endif
+              );
+        if (fd < 0)
+        {
+                BX_INFO(("redolog : could not open image %s", filename));
+                // open failed.
+                return -1;
+        }
+        BX_INFO(("redolog : open image %s", filename));
+      
+        res = ::read(fd, &header, sizeof(header));
+        if (res != STANDARD_HEADER_SIZE)
+        {
+               BX_PANIC(("redolog : could not read header")); 
+               return -1;
+        }
+
+        print_header();
+
+        if (strcmp((char*)header.standard.magic, STANDARD_HEADER_MAGIC) != 0)
+        {
+               BX_PANIC(("redolog : Bad header magic")); 
+               return -1;
+        }
+
+        if (strcmp((char*)header.standard.type, REDOLOG_TYPE) != 0)
+        {
+               BX_PANIC(("redolog : Bad header type")); 
+               return -1;
+        }
+        if (strcmp((char*)header.standard.subtype, type) != 0)
+        {
+               BX_PANIC(("redolog : Bad header subtype")); 
+               return -1;
+        }
+
+        if (dtoh32(header.standard.version) != STANDARD_HEADER_VERSION)
+        {
+               BX_PANIC(("redolog : Bad header version")); 
+               return -1;
+        }
+
+        catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
+        
+        // FIXME could mmap
+        ::lseek(fd,dtoh32(header.standard.header),SEEK_SET);
+        res = ::read(fd, catalog, dtoh32(header.specific.catalog) * sizeof(Bit32u)) ;
+
+        if (res !=  (ssize_t)(dtoh32(header.specific.catalog) * sizeof(Bit32u)))
+        {
+               BX_PANIC(("redolog : could not read catalog %d=%d",res, dtoh32(header.specific.catalog))); 
+               return -1;
+        }
+
+        // check last used extent
+        extent_next = 0;
+        for (Bit32u i=0; i < dtoh32(header.specific.catalog); i++)
+        {
+                if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED)
+                {
+                        if (dtoh32(catalog[i]) >= extent_next)
+                                extent_next = dtoh32(catalog[i]) + 1;
+                }
+        }
+        BX_INFO(("redolog : next extent will be at index %d",extent_next));
+      
+        // memory used for storing bitmaps
+        bitmap = (Bit8u *)malloc(dtoh32(header.specific.bitmap));
+
+        bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
+        extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
+
+        BX_DEBUG(("redolog : each bitmap is %d blocs", bitmap_blocs));
+        BX_DEBUG(("redolog : each extent is %d blocs", extent_blocs));
+
+        return 0;
+}
+
+void 
+redolog_t::close ()
+{
+        if (fd >= 0)
+                ::close(fd);
+
+        if (catalog != NULL)
+                free(catalog);
+
+        if (bitmap != NULL)
+                free(bitmap);
+}
+
+off_t
+redolog_t::lseek (off_t offset, int whence)
+{
+        if ((offset % 512) != 0) {
+                BX_PANIC( ("redolog : lseek HD with offset not multiple of 512"));
+                return -1;
+        }
+        if (whence != SEEK_SET) {
+                BX_PANIC( ("redolog : lseek HD with whence not SEEK_SET"));
+                return -1;
+        }
+        if (offset > (off_t)dtoh64(header.specific.disk))
+        {
+                BX_PANIC(("redolog : lseek to byte %ld failed", (long)offset));
+                return -1;
+        }
+
+        extent_index = offset / dtoh32(header.specific.extent);
+        extent_offset = (offset % dtoh32(header.specific.extent)) / 512;
+
+        BX_DEBUG(("redolog : lseeking extent index %d, offset %d",extent_index, extent_offset));
+
+        return offset;
+}
+
+ssize_t
+redolog_t::read (void* buf, size_t count)
+{
+        off_t bloc_offset, bitmap_offset;
+
+        if (count != 512)
+                BX_PANIC( ("redolog : read HD with count not 512"));
+
+        BX_DEBUG(("redolog : reading index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
+
+        if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
+        {
+                // page not allocated
+                return 0;
+        }
+
+        bitmap_offset  = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+        bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs); 
+        bloc_offset    = bitmap_offset + ((off_t)512 * (bitmap_blocs + extent_offset));
+
+        BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
+        BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
+
+
+        // FIXME if same extent_index as before we can skip bitmap read
+
+        ::lseek(fd, bitmap_offset, SEEK_SET);
+
+        if (::read(fd, bitmap,  dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
+        {
+                BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
+                return 0;
+        }
+
+        if ( ((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00 )
+        {
+                BX_DEBUG(("read not in redolog"));
+
+                // bitmap says bloc not in reloglog
+                return 0;
+        }
+        
+        ::lseek(fd, bloc_offset, SEEK_SET);
+
+        return (::read(fd, buf, count));
+}
+
+ssize_t
+redolog_t::write (const void* buf, size_t count)
+{
+        Bit32u i;
+        off_t bloc_offset, bitmap_offset, catalog_offset;
+        ssize_t written;
+        bx_bool update_catalog = 0;
+
+        if (count != 512)
+                BX_PANIC( ("redolog : write HD with count not 512"));
+
+        BX_DEBUG(("redolog : writing index %d, mapping to %d", extent_index, dtoh32(catalog[extent_index])));
+        if (dtoh32(catalog[extent_index]) == REDOLOG_PAGE_NOT_ALLOCATED)
+        {
+                if(extent_next >= dtoh32(header.specific.catalog))
+                {
+                        BX_PANIC(("redolog : can't allocate new extent... catalog is full"));
+                        return 0;
+                }
+
+                BX_DEBUG(("redolog : allocating new extent at %d", extent_next));
+
+                // Extent not allocated, allocate new
+                catalog[extent_index] = htod32(extent_next);
+                
+                extent_next += 1;
+
+                char *zerobuffer = (char*)malloc(512);
+                memset(zerobuffer, 0, 512);
+
+                // Write bitmap
+                bitmap_offset  = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+                bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs); 
+                ::lseek(fd, bitmap_offset, SEEK_SET);
+                for(i=0; i<bitmap_blocs; i++)
+                {
+                        ::write(fd, zerobuffer, 512);
+                }
+                // Write extent
+                for(i=0; i<extent_blocs; i++)
+                {
+                        ::write(fd, zerobuffer, 512);
+                }
+
+                free(zerobuffer);
+
+                update_catalog = 1;
+        }
+
+        bitmap_offset  = (off_t)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
+        bitmap_offset += (off_t)512 * dtoh32(catalog[extent_index]) * (extent_blocs + bitmap_blocs); 
+        bloc_offset    = bitmap_offset + ((off_t)512 * (bitmap_blocs + extent_offset));
+
+        BX_DEBUG(("redolog : bitmap offset is %x", (Bit32u)bitmap_offset));
+        BX_DEBUG(("redolog : bloc offset is %x", (Bit32u)bloc_offset));
+
+        // Write bloc
+        ::lseek(fd, bloc_offset, SEEK_SET);
+        written = ::write(fd, buf, count);
+
+        // Write bitmap
+        // FIXME if same extent_index as before we can skip bitmap read
+        ::lseek(fd, bitmap_offset, SEEK_SET);
+        if (::read(fd, bitmap,  dtoh32(header.specific.bitmap)) != (ssize_t)dtoh32(header.specific.bitmap))
+        {
+                BX_PANIC(("redolog : failed to read bitmap for extent %d", extent_index));
+                return 0;
+        }
+
+        // If bloc does not belong to extent yet
+        if ( ((bitmap[extent_offset/8] >> (extent_offset%8)) & 0x01) == 0x00 )
+        {
+                bitmap[extent_offset/8] |= 1 << (extent_offset%8);
+                ::lseek(fd, bitmap_offset, SEEK_SET);
+                ::write(fd, bitmap,  dtoh32(header.specific.bitmap));
+        }
+
+        // Write catalog
+        if (update_catalog)
+        {
+                // FIXME if mmap
+                catalog_offset  = (off_t)STANDARD_HEADER_SIZE + (extent_index * sizeof(Bit32u));
+
+                BX_DEBUG(("redolog : writing catalog at offset %x", (Bit32u)catalog_offset));
+
+                ::lseek(fd, catalog_offset, SEEK_SET);
+                ::write(fd, &catalog[extent_index], sizeof(Bit32u));
+        }
+
+        return written;
+}
+
+
+/*** growing_image_t function definitions ***/
+
+growing_image_t::growing_image_t(Bit64u _size)
+{
+        redolog = new redolog_t();
+        size = _size;
+}
+
+int growing_image_t::open (const char* pathname)
+{
+        int filedes = redolog->open(pathname,REDOLOG_SUBTYPE_GROWING,size);
+        BX_INFO(("'growing' disk opened, growing file is '%s'", pathname));
+        return filedes;
+}
+
+void growing_image_t::close ()
+{
+        redolog->close();
+}
+
+off_t growing_image_t::lseek (off_t offset, int whence)
+{
+      return redolog->lseek(offset, whence);
+}
+
+ssize_t growing_image_t::read (void* buf, size_t count)
+{
+      memset(buf, 0, count);
+      redolog->read((char*) buf, count);
+      return count;
+}
+
+ssize_t growing_image_t::write (const void* buf, size_t count)
+{
+      return redolog->write((char*) buf, count);
+}
+
+
+/*** undoable_image_t function definitions ***/
+
+undoable_image_t::undoable_image_t(Bit64u _size, const char* _redolog_name)
+{
+        redolog = new redolog_t();
+        ro_disk = new default_image_t();
+        size = _size;
+        redolog_name = NULL;
+        if (_redolog_name != NULL) {
+          if (strcmp(_redolog_name,"") != 0) {
+            redolog_name = strdup(_redolog_name);
+          }
+        }
+}
+
+int undoable_image_t::open (const char* pathname)
+{
+        char *logname=NULL;
+
+        if (ro_disk->open(pathname, O_RDONLY)<0)
+                return -1;
+
+        // if redolog name was set 
+        if ( redolog_name != NULL) {
+                if ( strcmp(redolog_name, "") != 0 ) {
+                        logname = (char*)malloc(strlen(redolog_name) + 1);
+                        strcpy (logname, redolog_name);
+                }
+        }
+
+        // Otherwise we make up the redolog filename from the pathname
+        if ( logname == NULL) {
+                logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
+                sprintf (logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
+        }
+
+        if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE,size) < 0)
+        {
+                if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, size) < 0)
+                {
+                        BX_PANIC(("Can't open or create redolog '%s'",logname));
+                        return -1;
+                }
+        }
+
+        BX_INFO(("'undoable' disk opened: ro-file is '%s', redolog is '%s'", pathname, logname));
+        free(logname);
+
+        return 0;
+}
+
+void undoable_image_t::close ()
+{
+        redolog->close();
+        ro_disk->close();
+
+        if (redolog_name!=NULL)
+          free(redolog_name);
+}
+
+off_t undoable_image_t::lseek (off_t offset, int whence)
+{
+      redolog->lseek(offset, whence);
+      return ro_disk->lseek(offset, whence);
+}
+
+ssize_t undoable_image_t::read (void* buf, size_t count)
+{
+      // This should be fixed if count != 512
+      if ((size_t)redolog->read((char*) buf, count) != count)
+              return ro_disk->read((char*) buf, count);
+      else 
+              return count;
+}
+
+ssize_t undoable_image_t::write (const void* buf, size_t count)
+{
+      return redolog->write((char*) buf, count);
+}
+
+
+/*** volatile_image_t function definitions ***/
+
+volatile_image_t::volatile_image_t(Bit64u _size, const char* _redolog_name)
+{
+        redolog = new redolog_t();
+        ro_disk = new default_image_t();
+        size = _size;
+        redolog_temp = NULL;
+        redolog_name = NULL;
+        if (_redolog_name != NULL) {
+          if (strcmp(_redolog_name,"") != 0) {
+            redolog_name = strdup(_redolog_name);
+          }
+        }
+}
+
+int volatile_image_t::open (const char* pathname)
+{
+        int filedes;
+        const char *logname=NULL;
+
+        if (ro_disk->open(pathname, O_RDONLY)<0)
+                return -1;
+
+        // if redolog name was set 
+        if ( redolog_name != NULL) {
+                if ( strcmp(redolog_name, "") != 0 ) {
+                        logname = redolog_name;
+                }
+        }
+
+        // otherwise use pathname as template
+        if (logname == NULL) {
+                logname = pathname;
+        }
+
+        redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
+        sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
+
+        filedes = mkstemp (redolog_temp);
+
+        if (filedes < 0)
+        {
+                BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+                return -1;
+        }
+        if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, size) < 0)
+        {
+                BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+                return -1;
+        }
+        
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+        // on unix it is legal to delete an open file
+        unlink(redolog_temp);
+#endif
+
+        BX_INFO(("'volatile' disk opened: ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
+
+        return 0;
+}
+
+void volatile_image_t::close ()
+{
+        redolog->close();
+        ro_disk->close();
+
+#if defined(WIN32) || BX_WITH_MACOS
+        // on non-unix we have to wait till the file is closed to delete it
+        unlink(redolog_temp);
+#endif
+        if (redolog_temp!=NULL)
+          free(redolog_temp);
+
+        if (redolog_name!=NULL)
+          free(redolog_name);
+}
+
+off_t volatile_image_t::lseek (off_t offset, int whence)
+{
+      redolog->lseek(offset, whence);
+      return ro_disk->lseek(offset, whence);
+}
+
+ssize_t volatile_image_t::read (void* buf, size_t count)
+{
+      // This should be fixed if count != 512
+      if ((size_t)redolog->read((char*) buf, count) != count)
+              return ro_disk->read((char*) buf, count);
+      else 
+              return count;
+}
+
+ssize_t volatile_image_t::write (const void* buf, size_t count)
+{
+      return redolog->write((char*) buf, count);
+}
+
+#if BX_COMPRESSED_HD_SUPPORT
+
+/*** z_ro_image_t function definitions ***/
+
+z_ro_image_t::z_ro_image_t()
+{
+        offset = (off_t)0;
+}
+
+int z_ro_image_t::open (const char* pathname)
+{
+        fd = ::open(pathname, O_RDONLY
+#ifdef O_BINARY
+                 | O_BINARY
+#endif
+           );
+
+        if(fd < 0)
+        {
+              BX_PANIC(("Could not open '%s' file", pathname));
+              return fd;
+        }
+
+        gzfile = gzdopen(fd, "rb");
+}
+
+void z_ro_image_t::close ()
+{
+        if (fd > -1) {
+            gzclose(gzfile);
+           // ::close(fd);
+        }
+}
+
+off_t z_ro_image_t::lseek (off_t _offset, int whence)
+{
+        // Only SEEK_SET supported
+        if (whence != SEEK_SET)
+        {
+              BX_PANIC(("lseek on compressed images : only SEEK_SET supported"));
+        }
+
+        // Seeking is expensive on compressed files, so we do it
+        // only when necessary, at the latest moment
+        offset = _offset;
+
+        return offset;
+}
+
+ssize_t z_ro_image_t::read (void* buf, size_t count)
+{
+      gzseek(gzfile, offset, SEEK_SET);
+      return gzread(gzfile, buf, count);
+}
+
+ssize_t z_ro_image_t::write (const void* buf, size_t count)
+{
+      BX_PANIC(("z_ro_image: write not supported"));
+      return 0;
+}
+
+
+/*** z_undoable_image_t function definitions ***/
+
+z_undoable_image_t::z_undoable_image_t(Bit64u _size, const char* _redolog_name)
+{
+        redolog = new redolog_t();
+        ro_disk = new z_ro_image_t();
+        size = _size;
+
+        redolog_name = NULL;
+        if (_redolog_name != NULL) {
+          if (strcmp(_redolog_name,"") != 0) {
+            redolog_name = strdup(_redolog_name);
+          }
+        }
+}
+
+int z_undoable_image_t::open (const char* pathname)
+{
+        char *logname=NULL;
+
+        if (ro_disk->open(pathname)<0)
+                return -1;
+
+        // If redolog name was set 
+        if ( redolog_name != NULL) {
+                if ( strcmp(redolog_name, "") != 0) {
+                        logname = (char*)malloc(strlen(redolog_name) + 1);
+                        strcpy (logname, redolog_name);
+                }
+        }
+
+        // Otherwise we make up the redolog filename from the pathname
+        if ( logname == NULL) {
+                logname = (char*)malloc(strlen(pathname) + UNDOABLE_REDOLOG_EXTENSION_LENGTH + 1);
+                sprintf (logname, "%s%s", pathname, UNDOABLE_REDOLOG_EXTENSION);
+        }
+
+        if (redolog->open(logname,REDOLOG_SUBTYPE_UNDOABLE,size) < 0)
+        {
+                if (redolog->create(logname, REDOLOG_SUBTYPE_UNDOABLE, size) < 0)
+                {
+                        BX_PANIC(("Can't open or create redolog '%s'",logname));
+                        return -1;
+                }
+        }
+
+        BX_INFO(("'z-undoable' disk opened, z-ro-file is '%s', redolog is '%s'", pathname, logname));
+        free(logname);
+
+        return 0;
+}
+
+void z_undoable_image_t::close ()
+{
+        redolog->close();
+        ro_disk->close();
+
+        if (redolog_name!=NULL)
+          free(redolog_name);
+}
+
+off_t z_undoable_image_t::lseek (off_t offset, int whence)
+{
+      redolog->lseek(offset, whence);
+      return ro_disk->lseek(offset, whence);
+}
+
+ssize_t z_undoable_image_t::read (void* buf, size_t count)
+{
+      // This should be fixed if count != 512
+      if (redolog->read((char*) buf, count) != count)
+              return ro_disk->read((char*) buf, count);
+      else 
+              return count;
+}
+
+ssize_t z_undoable_image_t::write (const void* buf, size_t count)
+{
+      return redolog->write((char*) buf, count);
+}
+
+
+/*** z_volatile_image_t function definitions ***/
+
+z_volatile_image_t::z_volatile_image_t(Bit64u _size, const char* _redolog_name)
+{
+        redolog = new redolog_t();
+        ro_disk = new z_ro_image_t();
+        size = _size;
+
+        redolog_temp = NULL;
+        redolog_name = NULL;
+        if (_redolog_name != NULL) {
+          if (strcmp(_redolog_name,"") != 0) {
+            redolog_name = strdup(_redolog_name);
+          }
+        }
+}
+
+int z_volatile_image_t::open (const char* pathname)
+{
+        int filedes;
+        const char *logname=NULL;
+
+        if (ro_disk->open(pathname)<0)
+                return -1;
+
+        // if redolog name was set 
+        if ( redolog_name != NULL) {
+                if ( strcmp(redolog_name, "") !=0 ) {
+                        logname = redolog_name;
+                }
+        }
+
+        // otherwise use pathname as template
+        if (logname == NULL) {
+                logname = pathname;
+        }
+
+        redolog_temp = (char*)malloc(strlen(logname) + VOLATILE_REDOLOG_EXTENSION_LENGTH + 1);
+        sprintf (redolog_temp, "%s%s", logname, VOLATILE_REDOLOG_EXTENSION);
+
+        filedes = mkstemp (redolog_temp);
+
+        if (filedes < 0)
+        {
+                BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+                return -1;
+        }
+        if (redolog->create(filedes, REDOLOG_SUBTYPE_VOLATILE, size) < 0)
+        {
+                BX_PANIC(("Can't create volatile redolog '%s'", redolog_temp));
+                return -1;
+        }
+        
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+        // on unix it is legal to delete an open file
+        unlink(redolog_temp);
+#endif
+
+        BX_INFO(("'z-volatile' disk opened: z-ro-file is '%s', redolog is '%s'", pathname, redolog_temp));
+
+        return 0;
+}
+
+void z_volatile_image_t::close ()
+{
+        redolog->close();
+        ro_disk->close();
+
+#if defined(WIN32) || BX_WITH_MACOS
+        // on non-unix we have to wait till the file is closed to delete it
+        unlink(redolog_temp);
+#endif
+
+        if (redolog_temp!=NULL)
+          free(redolog_temp);
+
+        if (redolog_name!=NULL)
+          free(redolog_name);
+}
+
+off_t z_volatile_image_t::lseek (off_t offset, int whence)
+{
+      redolog->lseek(offset, whence);
+      return ro_disk->lseek(offset, whence);
+}
+
+ssize_t z_volatile_image_t::read (void* buf, size_t count)
+{
+      // This should be fixed if count != 512
+      if (redolog->read((char*) buf, count) != count)
+              return ro_disk->read((char*) buf, count);
+      else 
+              return count;
+}
+
+ssize_t z_volatile_image_t::write (const void* buf, size_t count)
+{
+      return redolog->write((char*) buf, count);
+}
+
+
+#endif
diff --git a/tools/ioemu/iodev/harddrv.h b/tools/ioemu/iodev/harddrv.h
new file mode 100644 (file)
index 0000000..9320e61
--- /dev/null
@@ -0,0 +1,765 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: harddrv.h,v 1.22.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// SPARSE IMAGES HEADER
+#define SPARSE_HEADER_MAGIC  (0x02468ace)
+#define SPARSE_HEADER_VERSION  1
+#define SPARSE_HEADER_SIZE        (256) // Plenty of room for later
+#define SPARSE_PAGE_NOT_ALLOCATED (0xffffffff)
+
+ typedef struct
+ {
+   uint32  magic;
+   uint32  version;
+   uint32  pagesize;
+   uint32  numpages;
+
+   uint32  padding[60];
+ } sparse_header_t;
+
+#define STANDARD_HEADER_MAGIC     "Bochs Virtual HD Image"
+#define STANDARD_HEADER_VERSION   (0x00010000)
+#define STANDARD_HEADER_SIZE      (512)
+
+
+ // WARNING : headers are kept in x86 (little) endianness
+ typedef struct
+ {
+   Bit8u   magic[32];
+   Bit8u   type[16];
+   Bit8u   subtype[16];
+   Bit32u  version;
+   Bit32u  header;
+ } standard_header_t;
+
+#define REDOLOG_TYPE "Redolog"
+#define REDOLOG_SUBTYPE_UNDOABLE "Undoable"
+#define REDOLOG_SUBTYPE_VOLATILE "Volatile"
+#define REDOLOG_SUBTYPE_GROWING  "Growing"
+// #define REDOLOG_SUBTYPE_Z_UNDOABLE "z-Undoable"
+// #define REDOLOG_SUBTYPE_Z_VOLATILE "z-Volatile"
+
+#define REDOLOG_PAGE_NOT_ALLOCATED (0xffffffff)
+
+#define UNDOABLE_REDOLOG_EXTENSION ".redolog"
+#define UNDOABLE_REDOLOG_EXTENSION_LENGTH (strlen(UNDOABLE_REDOLOG_EXTENSION))
+#define VOLATILE_REDOLOG_EXTENSION ".XXXXXX"
+#define VOLATILE_REDOLOG_EXTENSION_LENGTH (strlen(VOLATILE_REDOLOG_EXTENSION))
+
+ typedef struct
+ {
+   // the fields in the header are kept in little endian
+   Bit32u  catalog;    // #entries in the catalog
+   Bit32u  bitmap;     // bitmap size in bytes
+   Bit32u  extent;     // extent size in bytes
+   Bit64u  disk;       // disk size in bytes
+ } redolog_specific_header_t;
+
+ typedef struct
+ {
+   standard_header_t standard;
+   redolog_specific_header_t specific;
+
+   Bit8u padding[STANDARD_HEADER_SIZE - (sizeof (standard_header_t) + sizeof (redolog_specific_header_t))];
+ } redolog_header_t;
+
+// htod : convert host to disk (little) endianness
+// dtoh : convert disk (little) to host endianness
+#if defined (BX_LITTLE_ENDIAN)
+#define htod32(val) (val)
+#define dtoh32(val) (val)
+#define htod64(val) (val)
+#define dtoh64(val) (val)
+#else
+#define htod32(val) ( (((val)&0xff000000)>>24) | (((val)&0xff0000)>>8) | (((val)&0xff00)<<8) | (((val)&0xff)<<24) )
+#define dtoh32(val) htod32(val)
+#define htod64(val) ( (((val)&0xff00000000000000LL)>>56) | (((val)&0xff000000000000LL)>>40) | (((val)&0xff0000000000LL)>>24) | (((val)&0xff00000000LL)>>8) | (((val)&0xff000000LL)<<8) | (((val)&0xff0000LL)<<24) | (((val)&0xff00LL)<<40) | (((val)&0xffLL)<<56) )
+#define dtoh64(val) htod64(val)
+#endif
+
+#ifndef INCLUDE_ONLY_HD_HEADERS
+
+typedef enum _sense {
+      SENSE_NONE = 0, SENSE_NOT_READY = 2, SENSE_ILLEGAL_REQUEST = 5,
+      SENSE_UNIT_ATTENTION = 6
+} sense_t;
+
+typedef enum _asc {
+      ASC_INV_FIELD_IN_CMD_PACKET = 0x24,
+      ASC_MEDIUM_NOT_PRESENT = 0x3a,
+      ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39,
+      ASC_LOGICAL_BLOCK_OOR = 0x21
+} asc_t;
+
+class LOWLEVEL_CDROM;
+
+class device_image_t
+{
+  public:
+      // Open a image. Returns non-negative if successful.
+      virtual int open (const char* pathname) = 0;
+
+      // Close the image.
+      virtual void close () = 0;
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      virtual off_t lseek (off_t offset, int whence) = 0;
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      virtual ssize_t read (void* buf, size_t count) = 0;
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      virtual ssize_t write (const void* buf, size_t count) = 0;
+
+      unsigned cylinders;
+      unsigned heads;
+      unsigned sectors;
+};
+
+// FLAT MODE
+class default_image_t : public device_image_t
+{
+  public:
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Open an image with specific flags. Returns non-negative if successful.
+      int open (const char* pathname, int flags);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      int fd;
+
+};
+
+// CONCAT MODE
+class concat_image_t : public device_image_t
+{
+  public:
+      // Default constructor
+      concat_image_t();
+      
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+#define BX_CONCAT_MAX_IMAGES 8
+      int fd_table[BX_CONCAT_MAX_IMAGES];
+      off_t start_offset_table[BX_CONCAT_MAX_IMAGES];
+      off_t length_table[BX_CONCAT_MAX_IMAGES];
+      void increment_string (char *str);
+      int maxfd;  // number of entries in tables that are valid
+
+      // notice if anyone does sequential read or write without seek in between.
+      // This can be supported pretty easily, but needs additional checks.
+      // 0=something other than seek was last operation
+      // 1=seek was last operation
+      int seek_was_last_op;
+
+      // the following variables tell which partial image file to use for
+      // the next read and write.
+      int index;  // index into table
+      int fd;     // fd to use for reads and writes
+      off_t thismin, thismax; // byte offset boundary of this image
+};
+
+// SPARSE MODE
+class sparse_image_t : public device_image_t
+{
+
+// Format of a sparse file:
+// 256 byte header, containing details such as page size and number of pages
+// Page indirection table, mapping virtual pages to physical pages within file
+// Physical pages till end of file
+
+  public:
+      // Default constructor
+      sparse_image_t();
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+ int fd;
+
+#ifdef _POSIX_MAPPED_FILES
+ void *  mmap_header;
+ size_t  mmap_length;
+ size_t  system_pagesize_mask;
+#endif
+ uint32 *  pagetable;
+
+ // Header is written to disk in little-endian (x86) format
+ // Thus needs to be converted on big-endian systems before read
+ // The pagetable is also kept little endian
+
+ sparse_header_t header;
+
+ uint32  pagesize;
+ int     pagesize_shift;
+ uint32  pagesize_mask;
+
+ off_t   data_start;
+ off_t   underlying_filesize;
+
+ char *  pathname;
+
+ off_t position;
+
+ uint32 position_virtual_page;
+ uint32 position_physical_page;
+ uint32 position_page_offset;
+
+ off_t underlying_current_filepos;
+
+ off_t total_size;
+
+ void panic(const char * message);
+ off_t
+#ifndef PARANOID
+       sparse_image_t::
+#endif
+                       get_physical_offset();
+ void
+#ifndef PARANOID
+       sparse_image_t::
+#endif
+                       set_virtual_page(uint32 new_virtual_page);
+ void read_header();
+ ssize_t read_page_fragment(uint32 read_virtual_page, uint32 read_page_offset, size_t read_size, void * buf);
+
+ sparse_image_t *  parent_image;
+};
+
+#if EXTERNAL_DISK_SIMULATOR
+#include "external-disk-simulator.h"
+#endif
+
+#if DLL_HD_SUPPORT
+class dll_image_t : public device_image_t
+{
+  public:
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      int vunit,vblk;
+
+};
+#endif
+
+// REDOLOG class
+class redolog_t 
+{
+  public:
+      redolog_t();
+      int make_header (const char* type, Bit64u size);
+      int create (const char* filename, const char* type, Bit64u size);
+      int create (int filedes, const char* type, Bit64u size);
+      int open (const char* filename, const char* type, Bit64u size);
+      void close ();
+
+      off_t lseek (off_t offset, int whence);
+      ssize_t read (void* buf, size_t count);
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      void             print_header();
+      int              fd;
+      redolog_header_t header;     // Header is kept in x86 (little) endianness
+      Bit32u          *catalog;
+      Bit8u           *bitmap;
+      Bit32u           extent_index;
+      Bit32u           extent_offset;
+      Bit32u           extent_next;
+
+      Bit32u           bitmap_blocs;
+      Bit32u           extent_blocs;
+};
+
+// GROWING MODE
+class growing_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      growing_image_t(Bit64u size);
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      redolog_t *redolog;
+      Bit64u    size;
+};
+
+// UNDOABLE MODE
+class undoable_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      undoable_image_t(Bit64u size, const char* redolog_name);
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      redolog_t       *redolog;       // Redolog instance
+      default_image_t *ro_disk;       // Read-only flat disk instance
+      Bit64u          size;           
+      char            *redolog_name;  // Redolog name
+};
+
+
+// VOLATILE MODE
+class volatile_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      volatile_image_t(Bit64u size, const char* redolog_name);
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      redolog_t       *redolog;       // Redolog instance
+      default_image_t *ro_disk;       // Read-only flat disk instance
+      Bit64u          size;           
+      char            *redolog_name;  // Redolog name
+      char            *redolog_temp;  // Redolog temporary file name
+};
+
+
+#if BX_COMPRESSED_HD_SUPPORT
+
+#include <zlib.h>
+
+
+// Default compressed READ-ONLY image class
+class z_ro_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      z_ro_image_t();
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      off_t offset;
+      int fd;
+      gzFile gzfile;
+
+};
+
+// Z-UNDOABLE MODE
+class z_undoable_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      z_undoable_image_t(Bit64u size, const char* redolog_name);
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      redolog_t       *redolog;       // Redolog instance
+      z_ro_image_t    *ro_disk;       // Read-only compressed flat disk instance
+      Bit64u          size;           
+      char            *redolog_name;  // Redolog name
+};
+
+// Z-VOLATILE MODE
+class z_volatile_image_t : public device_image_t
+{
+  public:
+      // Contructor
+      z_volatile_image_t(Bit64u size, const char* redolog_name);
+
+      // Open a image. Returns non-negative if successful.
+      int open (const char* pathname);
+
+      // Close the image.
+      void close ();
+
+      // Position ourselves. Return the resulting offset from the
+      // beginning of the file.
+      off_t lseek (off_t offset, int whence);
+
+      // Read count bytes to the buffer buf. Return the number of
+      // bytes read (count).
+      ssize_t read (void* buf, size_t count);
+
+      // Write count bytes from buf. Return the number of bytes
+      // written (count).
+      ssize_t write (const void* buf, size_t count);
+
+  private:
+      redolog_t       *redolog;       // Redolog instance
+      z_ro_image_t    *ro_disk;       // Read-only compressed flat disk instance
+      Bit64u          size;           
+      char            *redolog_name;  // Redolog name
+      char            *redolog_temp;  // Redolog temporary file name
+};
+
+#endif
+
+
+typedef struct {
+  struct {
+    bx_bool busy;
+    bx_bool drive_ready;
+    bx_bool write_fault;
+    bx_bool seek_complete;
+    bx_bool drq;
+    bx_bool corrected_data;
+    bx_bool index_pulse;
+    unsigned index_pulse_count;
+    bx_bool err;
+    } status;
+  Bit8u    error_register;
+  Bit8u    head_no;
+  union {
+    Bit8u    sector_count;
+    struct {
+#ifdef BX_LITTLE_ENDIAN
+      unsigned c_d : 1;
+      unsigned i_o : 1;
+      unsigned rel : 1;
+      unsigned tag : 5;
+#else  /* BX_BIG_ENDIAN */
+      unsigned tag : 5;
+      unsigned rel : 1;
+      unsigned i_o : 1;
+      unsigned c_d : 1;
+#endif
+    } interrupt_reason;
+  };
+  Bit8u    sector_no;
+  union {
+    Bit16u   cylinder_no;
+    Bit16u   byte_count;
+  };
+  Bit8u    buffer[2048];
+  Bit32u   buffer_index;
+  Bit32u   drq_index;
+  Bit8u    current_command;
+  Bit8u    sectors_per_block;
+  Bit8u    lba_mode;
+  struct {
+    bx_bool reset;       // 0=normal, 1=reset controller
+    bx_bool disable_irq; // 0=allow irq, 1=disable irq
+    } control;
+  Bit8u    reset_in_progress;
+  Bit8u    features;
+  } controller_t;
+
+struct sense_info_t {
+  sense_t sense_key;
+  struct {
+    Bit8u arr[4];
+  } information;
+  struct {
+    Bit8u arr[4];
+  } specific_inf;
+  struct {
+    Bit8u arr[3];
+  } key_spec;
+  Bit8u fruc;
+  Bit8u asc;
+  Bit8u ascq;
+};
+
+struct error_recovery_t {
+  unsigned char data[8];
+
+  error_recovery_t ();
+};
+
+uint16 read_16bit(const uint8* buf) BX_CPP_AttrRegparmN(1);
+uint32 read_32bit(const uint8* buf) BX_CPP_AttrRegparmN(1);
+
+
+#ifdef LOWLEVEL_CDROM
+#  include "cdrom.h"
+#endif
+
+
+struct cdrom_t
+{
+  bx_bool ready;
+  bx_bool locked;
+#ifdef LOWLEVEL_CDROM
+  LOWLEVEL_CDROM* cd;
+#endif
+  uint32 capacity;
+  int next_lba;
+  int remaining_blocks;
+  struct currentStruct {
+    error_recovery_t error_recovery;
+  } current;
+};
+
+struct atapi_t
+{
+  uint8 command;
+  int drq_bytes;
+  int total_bytes_remaining;
+};
+
+#if BX_USE_HD_SMF
+#  define BX_HD_SMF  static
+#  define BX_HD_THIS theHardDrive->
+#else
+#  define BX_HD_SMF
+#  define BX_HD_THIS this->
+#endif
+
+typedef enum {
+      IDE_NONE, IDE_DISK, IDE_CDROM
+} device_type_t;
+
+class bx_hard_drive_c : public bx_hard_drive_stub_c {
+public:
+
+  bx_hard_drive_c(void);
+  virtual ~bx_hard_drive_c(void);
+  virtual void   close_harddrive(void);
+  virtual void   init();
+  virtual void   reset(unsigned type);
+  virtual Bit32u   get_device_handle(Bit8u channel, Bit8u device);
+  virtual Bit32u   get_first_cd_handle(void);
+  virtual unsigned get_cd_media_status(Bit32u handle);
+  virtual unsigned set_cd_media_status(Bit32u handle, unsigned status);
+
+  virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len) {
+    return read_handler (this, address, io_len);
+  }
+  virtual void virt_write_handler(Bit32u address, 
+      Bit32u value, unsigned io_len)
+  {
+    write_handler(this, address, value, io_len);
+  }
+#if !BX_USE_HD_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+
+private:
+
+  BX_HD_SMF bx_bool calculate_logical_address(Bit8u channel, off_t *sector) BX_CPP_AttrRegparmN(2);
+  BX_HD_SMF void increment_address(Bit8u channel) BX_CPP_AttrRegparmN(1);
+  BX_HD_SMF void identify_drive(Bit8u channel);
+  BX_HD_SMF void identify_ATAPI_drive(Bit8u channel);
+  BX_HD_SMF void command_aborted(Bit8u channel, unsigned command);
+
+  BX_HD_SMF void init_send_atapi_command(Bit8u channel, Bit8u command, int req_length, int alloc_length, bool lazy = false) BX_CPP_AttrRegparmN(3);
+  BX_HD_SMF void ready_to_send_atapi(Bit8u channel) BX_CPP_AttrRegparmN(1);
+  BX_HD_SMF void raise_interrupt(Bit8u channel) BX_CPP_AttrRegparmN(1);
+  BX_HD_SMF void atapi_cmd_error(Bit8u channel, sense_t sense_key, asc_t asc);
+  BX_HD_SMF void init_mode_sense_single(Bit8u channel, const void* src, int size);
+  BX_HD_SMF void atapi_cmd_nop(Bit8u channel) BX_CPP_AttrRegparmN(1);
+
+  // FIXME:
+  // For each ATA channel we should have one controller struct
+  // and an array of two drive structs
+  struct channel_t {
+    struct drive_t {
+      device_image_t* hard_drive;
+      device_type_t device_type;
+      // 512 byte buffer for ID drive command
+      // These words are stored in native word endian format, as
+      // they are fetched and returned via a return(), so
+      // there's no need to keep them in x86 endian format.
+      Bit16u id_drive[256];
+
+      controller_t controller;
+      cdrom_t cdrom;
+      sense_info_t sense;
+      atapi_t atapi;
+
+      Bit8u model_no[41];
+      } drives[2];
+    unsigned drive_select;
+
+    Bit16u ioaddr1;
+    Bit16u ioaddr2;
+    Bit8u  irq;
+
+    } channels[BX_MAX_ATA_CHANNEL];
+
+#if BX_PDC20230C_VLBIDE_SUPPORT
+// pdc20630c is only available for 1st ata channel
+  struct pdc20630c_t {
+    bx_bool prog_mode;
+    Bit8u   prog_count;
+    Bit32u  p1f3_value;
+    Bit32u  p1f4_value;
+    } pdc20230c;
+#endif
+
+  };
+#endif // INCLUDE_ONLY_SPARSE_HEADER
+
diff --git a/tools/ioemu/iodev/ioapic.cc b/tools/ioemu/iodev/ioapic.cc
new file mode 100644 (file)
index 0000000..8aaf67f
--- /dev/null
@@ -0,0 +1,175 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ioapic.cc,v 1.11 2002/11/19 05:47:45 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include <stdio.h>
+#include  "bochs.h"
+#if BX_SUPPORT_APIC
+
+class bx_ioapic_c bx_ioapic;
+#define LOG_THIS  bx_ioapic.
+
+void
+bx_io_redirect_entry_t::parse_value ()
+{
+  dest = (value >> 56) & 0xff;
+  masked = (value >> 16) & 1;
+  trig_mode = (value >> 15) & 1;
+  remote_irr = (value >> 14) & 1;
+  polarity = (value >> 13) & 1;
+  //delivery_status = (value >> 12) & 1;
+  delivery_status = 0;  // always say the message has gone through
+  dest_mode = (value >> 11) & 1;
+  delivery_mode = (value >> 8) & 7;
+  vector = (value >> 0) & 0xff;
+}
+
+void
+bx_io_redirect_entry_t::sprintf_self (char *buf)
+{
+  sprintf (buf, "dest=%02x, masked=%d, trig_mode=%d, remote_irr=%d, polarity=%d, delivery_status=%d, dest_mode=%d, delivery_mode=%d, vector=%02x", dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector);
+}
+
+bx_ioapic_c::bx_ioapic_c () 
+  : bx_generic_apic_c ()
+{
+  put("IOAP");
+  settype(IOAPICLOG);
+}
+
+bx_ioapic_c::~bx_ioapic_c () {
+}
+
+void 
+bx_ioapic_c::init () 
+{
+  bx_generic_apic_c::init ();
+  BX_DEBUG(("initializing I/O APIC"));
+  base_addr = 0xfec00000;
+  ioregsel = 0;
+  // all interrupts masked
+  for (int i=0; i<BX_IOAPIC_NUM_PINS; i++) {
+    ioredtbl[i].set_even_word (0x00010000);
+    ioredtbl[i].set_odd_word  (0x00000000);
+  }
+  irr = 0;
+}
+
+void 
+bx_ioapic_c::reset (unsigned type) 
+{
+}
+
+void 
+bx_ioapic_c::read_aligned(Bit32u address, Bit32u *data, unsigned len)
+{
+  BX_DEBUG( ("I/O APIC read_aligned addr=%08x, len=%d", address, len));
+  BX_ASSERT (len == 4);
+  address &= 0xff;
+  if (address == 0x00) {
+    // select register
+    *data = ioregsel;
+    return;
+  } else if (address != 0x10) {
+      BX_PANIC(("IOAPIC: read from unsupported address"));
+  }
+  // only reached when reading data register
+  switch (ioregsel) {
+  case 0x00:  // APIC ID
+    *data = ((id & 0xf) << 24);
+    return;
+  case 0x01:  // version
+    *data = (((BX_IOAPIC_NUM_PINS-1) & 0xff) << 16) 
+            | (BX_IOAPIC_VERSION_ID & 0x0f);
+    return;
+  case 0x02:
+    BX_INFO(("IOAPIC: arbitration ID unsupported, returned 0"));
+    *data = 0;
+    return;
+  default:
+    int index = (ioregsel - 0x10) >> 1;
+    if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
+      bx_io_redirect_entry_t *entry = ioredtbl + index;
+      *data = (ioregsel&1) ? entry->get_odd_word() : entry->get_even_word ();
+      return;
+    }
+    BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
+  }
+}
+
+void 
+bx_ioapic_c::write(Bit32u address, Bit32u *value, unsigned len)
+{
+  BX_DEBUG(("IOAPIC: write addr=%08x, data=%08x, len=%d", address, *value, len));
+  address &= 0xff;
+  if (address == 0x00)  {
+    ioregsel = *value;
+    return;
+  } else if (address != 0x10) {
+    BX_PANIC(("IOAPIC: write to unsupported address"));
+  }
+  // only reached when writing data register
+  switch (ioregsel) {
+    case 0x00: // set APIC ID
+      {
+       Bit8u newid = (*value >> 24) & 0xf;
+       BX_INFO(("IOAPIC: setting id to 0x%x", newid));
+       set_id (newid);
+       return;
+      }
+    case 0x01: // version
+    case 0x02: // arbitration id
+      BX_INFO(("IOAPIC: could not write, IOREGSEL=0x%02x", ioregsel));
+      return;
+    default:
+      int index = (ioregsel - 0x10) >> 1;
+      if (index >= 0 && index < BX_IOAPIC_NUM_PINS) {
+       bx_io_redirect_entry_t *entry = ioredtbl + index;
+       if (ioregsel&1) 
+         entry->set_odd_word (*value);
+       else 
+         entry->set_even_word (*value);
+       char buf[1024];
+       entry->sprintf_self (buf);
+       BX_DEBUG(("IOAPIC: now entry[%d] is %s", index, buf));
+       service_ioapic ();
+       return;
+      }
+      BX_PANIC(("IOAPIC: IOREGSEL points to undefined register %02x", ioregsel));
+  }
+}
+
+void bx_ioapic_c::trigger_irq (unsigned vector, unsigned from) 
+{
+  BX_DEBUG(("IOAPIC: received interrupt %d", vector));
+  if (vector >= 0 && vector < BX_IOAPIC_NUM_PINS) {
+    Bit32u bit = 1<<vector;
+    if ((irr & bit) == 0) {
+      irr |= bit;
+      service_ioapic ();
+    }
+  } else BX_PANIC(("IOAPIC: vector %d out of range", vector));
+}
+
+void bx_ioapic_c::untrigger_irq (unsigned num, unsigned from) 
+{
+  BX_DEBUG(("IOAPIC: interrupt %d went away", num));
+}
+
+void bx_ioapic_c::service_ioapic ()
+{
+  // look in IRR and deliver any interrupts that are not masked.
+  BX_DEBUG(("IOAPIC: servicing"));
+  for (unsigned bit=0; bit < BX_IOAPIC_NUM_PINS; bit++) {
+    if (irr & (1<<bit)) {
+      bx_io_redirect_entry_t *entry = ioredtbl + bit;
+      if (!entry->masked) {
+       // clear irr bit and deliver
+       bx_bool done = deliver (entry->dest, entry->dest_mode, entry->delivery_mode, entry->vector, entry->polarity, entry->trig_mode);
+       if (done) irr &= ~(1<<bit);
+      }
+    }
+  }
+}
+
+#endif /* if BX_SUPPORT_APIC */
diff --git a/tools/ioemu/iodev/ioapic.h b/tools/ioemu/iodev/ioapic.h
new file mode 100644 (file)
index 0000000..be008f0
--- /dev/null
@@ -0,0 +1,54 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ioapic.h,v 1.5 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+extern class bx_ioapic_c bx_ioapic;
+
+#define BX_IOAPIC_VERSION_ID 0x00170011  // same version as 82093 IOAPIC
+#define BX_IOAPIC_NUM_PINS 0x18
+
+class bx_io_redirect_entry_t {
+  Bit64u value;
+public:
+  Bit32u get_even_word () { return value & 0xffffffff; }
+  Bit32u get_odd_word () { return (value>>32) & 0xffffffff; }
+  void set_even_word (Bit32u even) {
+    // keep high 32 bits of value, replace low 32
+    value = ((value >> 32) << 32) | (even & 0xffffffff);
+    parse_value ();
+  }
+  void set_odd_word (Bit32u odd) { 
+    // keep low 32 bits of value, replace high 32
+    value = (((Bit64u)odd & 0xffffffff) << 32) | (value & 0xffffffff);
+    parse_value ();
+  }
+  void parse_value ();
+  // parse_value sets the value and all the fields below.  Do not change
+  // these fields except by calling parse_value.
+  Bit8u dest, masked, trig_mode, remote_irr, polarity, delivery_status, dest_mode, delivery_mode, vector;
+  void sprintf_self (char *buf);
+};
+
+class bx_ioapic_c : public bx_generic_apic_c {
+  Bit32u ioregsel;    // selects between various registers
+  // interrupt request bitmask, not visible from the outside.  Bits in the
+  // irr are set when trigger_irq is called, and cleared when the interrupt
+  // is delivered to the processor.  If an interrupt is masked, the irr
+  // will still be set but delivery will not occur until it is unmasked.
+  // It's not clear if this is how the real device works.
+  Bit32u irr;
+public:
+  bx_io_redirect_entry_t ioredtbl[BX_IOAPIC_NUM_PINS];  // table of redirections
+  bx_ioapic_c ();
+  ~bx_ioapic_c ();
+  virtual void init ();
+  virtual void reset (unsigned type);
+  virtual void read_aligned(Bit32u address, Bit32u *data, unsigned len);
+  virtual void write(Bit32u address, Bit32u *value, unsigned len);
+  void trigger_irq (unsigned num, unsigned from);
+  void untrigger_irq (unsigned num, unsigned from);
+  void service_ioapic ();
+  virtual bx_bool match_logical_addr (Bit8u address) { return false; }
+  virtual bx_bool is_local_apic () { return false; }
+  virtual bx_apic_type_t get_type () { return APIC_TYPE_IOAPIC; }
+};
diff --git a/tools/ioemu/iodev/iodebug.cc b/tools/ioemu/iodev/iodebug.cc
new file mode 100644 (file)
index 0000000..ca2314e
--- /dev/null
@@ -0,0 +1,354 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodebug.cc,v 1.15 2002/11/19 05:47:45 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include "bochs.h"
+#if BX_IODEBUG_SUPPORT
+
+
+
+bx_iodebug_c bx_iodebug;
+bx_iodebug_c *bx_iodebug_ptr;
+
+  struct bx_iodebug_s_type {
+    bx_bool enabled;
+    unsigned int register_select;
+    Bit32u registers[2];
+    Bit32u monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
+    Bit32u monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
+  } bx_iodebug_s;
+
+
+
+
+// Constructor
+bx_iodebug_c::bx_iodebug_c( void )
+{
+  put("IODEBUG");
+  settype(IODEBUGLOG);
+
+}
+
+
+
+
+
+// Destructor
+bx_iodebug_c::~bx_iodebug_c( void )
+{
+}
+
+
+
+
+
+void bx_iodebug_c::init(void)
+{
+  int i;
+
+  DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 7);
+  DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 7);
+  DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 7);
+//  fprintf( stderr, "IODEBUG initialized\n");
+
+  bx_iodebug_s.enabled = 0;
+  bx_iodebug_s.register_select = 0;
+  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
+    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
+    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
+  }
+}
+
+void bx_iodebug_c::reset(unsigned type)
+{
+}
+
+
+Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
+{
+  bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
+  return( bx_iodebug_ptr->read(addr, io_len) );
+}
+
+
+
+
+
+
+Bit32u bx_iodebug_c::read( Bit32u addr, unsigned io_len )
+{
+
+  if(bx_iodebug_s.enabled) return(0x8A00);
+  return(0);
+}
+
+
+
+
+
+
+
+
+
+
+void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
+{
+  bx_iodebug_c *class_ptr = (bx_iodebug_c *) this_ptr;
+  class_ptr->write( addr, dvalue, io_len );
+}
+
+
+
+
+
+
+void bx_iodebug_c::write( Bit32u addr, Bit32u dvalue, unsigned int io_len )
+{
+
+
+//  fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned int)addr, (unsigned int)dvalue, io_len);
+
+  if( addr == 0x8A01 && io_len == 2 )
+  {
+      bx_iodebug_s.registers[bx_iodebug_s.register_select] =
+        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
+       (dvalue & 0x0000FFFF );
+  }
+
+  if( (addr != 0x8A00) || (io_len != 2) ) return;
+
+  if( !bx_iodebug_s.enabled )
+  {
+    if( dvalue == 0x8A00 )
+    {
+      bx_iodebug_s.enabled = 1;
+//      fprintf(stderr, "IODEBUG enabled\n");
+      bx_iodebug_s.registers[0] = 0;
+      bx_iodebug_s.registers[1] = 0;
+    }
+    return;
+  }
+
+  switch( dvalue )
+  {
+    case( 0x8A01 ):
+      bx_iodebug_s.register_select = 0;
+//      fprintf( stderr, "IODEBUG register 0 selected\n");
+      break;
+
+    case( 0x8A02 ):
+      bx_iodebug_s.register_select = 1;
+//      fprintf( stderr, "IODEBUG register 1 selected\n");
+      break;
+
+    case( 0x8A80 ):
+      bx_iodebug_s.register_select = 0;
+      bx_iodebug_c::add_range(
+          bx_iodebug_s.registers[0],
+         bx_iodebug_s.registers[1]);
+      bx_iodebug_s.registers[0] = 0;
+      bx_iodebug_s.registers[1] = 0;
+      break;
+
+#if BX_DEBUGGER
+    case( 0x8AE0 ):
+      fprintf( stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
+      bx_guard.interrupt_requested=1;
+      break;
+
+    case( 0x8AE2):
+      fprintf( stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
+      BX_CPU(dbg_cpu)->trace = 0;
+      break;
+
+    case( 0x8AE3 ):
+      fprintf( stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
+      BX_CPU(dbg_cpu)->trace = 1;
+      break;
+
+    case( 0x8AE4 ):
+      fprintf( stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
+      BX_CPU(dbg_cpu)->trace_reg = 0;
+      break;
+
+    case( 0x8AE5 ):
+      fprintf( stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
+      BX_CPU(dbg_cpu)->trace_reg = 1;
+      break;
+
+#endif
+
+    case( 0x8AFF ):
+      bx_iodebug_s.enabled = 0;
+//      fprintf( stderr, "IODEBUG device deactivated\n");
+//      break;
+
+//    default:
+//      fprintf(stderr,"IODEBUG unsupported register code\n");
+  }
+}
+
+
+
+
+
+
+
+
+// Static function
+void bx_iodebug_c::mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+  Bit32u data32;
+  Bit16u data16;
+  Bit8u  data8;
+
+  unsigned int area;
+  if( !bx_iodebug_s.enabled ) return;
+
+  area = bx_iodebug_c::range_test( addr, len );
+  // Device is enabled, testing address ranges
+  if( area )
+  {
+    area--;
+#if BX_DEBUGGER
+  fprintf( stdout, "%s @ eip: %08X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
+  bx_guard.interrupt_requested=1;
+#else
+    fprintf( stderr,
+             "IODEBUG write to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
+            area,
+            cpu->get_EIP(),
+            bx_iodebug_s.monitored_mem_areas_start[area],
+            bx_iodebug_s.monitored_mem_areas_end[area],
+            (unsigned int)addr);
+
+    data32 = * (Bit32u *)data;
+    data16 = (Bit16u)data32;
+    data8  = (Bit8u)data32;
+
+    switch(len)
+    {
+      case(1):
+        fprintf(stderr,"%02X\n", (unsigned int)data8);
+       break;
+
+      case(2):
+        fprintf(stderr,"%04X\n", (unsigned int)data16);
+       break;
+
+      case(4):
+        fprintf(stderr,"%08X\n", (unsigned int)data32);
+       break;
+
+      default:
+        fprintf(stderr, "unsupported write size\n");
+    }
+#endif
+  }
+}
+
+
+
+
+
+
+
+
+void bx_iodebug_c::mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+  Bit32u data32;
+  Bit16u data16;
+  Bit8u  data8;
+
+  unsigned int area;
+  if( !bx_iodebug_s.enabled ) return;
+
+  area = bx_iodebug_c::range_test( addr, len );
+  // Device is enabled, testing address ranges
+  if( area )
+  {
+    area--;
+#if BX_DEBUGGER
+  fprintf( stdout, "%s @ eip: %8X wrote at monitored memory location %8X\n", cpu->name, cpu->get_EIP(), addr);
+  bx_guard.interrupt_requested=1;
+#else
+    fprintf( stderr,
+             "IODEBUG read to monitored memory area: %2i\tby EIP:\t\t%08X\n\trange start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
+            area,
+            cpu->get_EIP(),
+            bx_iodebug_s.monitored_mem_areas_start[area],
+            bx_iodebug_s.monitored_mem_areas_end[area],
+            (unsigned int)addr);
+    data32 = * (Bit32u *)data;
+    data16 = (Bit16u)data32;
+    data8  = (Bit8u)data32;
+
+    switch(len)
+    {
+      case(1):
+        fprintf(stderr,"%02X\n", (unsigned int)data8);
+       break;
+
+      case(2):
+        fprintf(stderr,"%04X\n", (unsigned int)data16);
+       break;
+
+      case(4):
+        fprintf(stderr,"%08X\n", (unsigned int)data32);
+       break;
+
+      default:
+        fprintf(stderr, "unsupported write size\n");
+    }
+#endif
+  }
+}
+
+
+
+
+
+
+
+unsigned int bx_iodebug_c::range_test( Bit32u addr, unsigned int len )
+{
+  unsigned int i;
+
+  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
+  {
+    if( (bx_iodebug_s.monitored_mem_areas_start[i]!=0) ||
+        (bx_iodebug_s.monitored_mem_areas_end[i]!=0) )
+    {
+      if( (Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i] )
+        continue;
+      if( addr < bx_iodebug_s.monitored_mem_areas_end[i] )
+      {
+        return(++i);
+      }
+    }  
+  }
+  return(0);
+}
+
+
+
+
+
+
+void bx_iodebug_c::add_range( Bit32u addr_start, Bit32u addr_end )
+{
+  unsigned int i;
+  for(i=0;i<BX_IODEBUG_MAX_AREAS;i++)
+  {
+    if( !bx_iodebug_s.monitored_mem_areas_start[i] &&
+        !bx_iodebug_s.monitored_mem_areas_end[i] )
+    {
+       bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
+       bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
+//     fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
+       return;
+    }
+  }
+//  fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
+}
+#endif /* if BX_IODEBUG_SUPPORT */
diff --git a/tools/ioemu/iodev/iodebug.h b/tools/ioemu/iodev/iodebug.h
new file mode 100644 (file)
index 0000000..a31f7cf
--- /dev/null
@@ -0,0 +1,35 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodebug.h,v 1.7 2002/10/26 03:53:22 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#ifndef _BX_IODEBUG_H
+#define _BX_IODEBUG_H
+
+#include "config.h"
+
+#define BX_IODEBUG_THIS this->
+
+#define BX_IODEBUG_MAX_AREAS   30
+
+class bx_iodebug_c : public bx_devmodel_c
+{
+public:
+  bx_iodebug_c( void );
+  ~bx_iodebug_c( void );
+  virtual void init(void);
+  virtual void reset (unsigned type);
+  static void mem_write( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+  static void mem_read( BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data);
+
+private:
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  Bit32u read(Bit32u addr, unsigned int io_len);
+  void write(Bit32u addr, Bit32u dvalue, unsigned int io_len);
+  static unsigned int range_test(Bit32u addr, unsigned int len);
+  static void add_range( Bit32u addr_start, Bit32u addr_end);
+
+};
+
+extern bx_iodebug_c bx_iodebug;
+#endif
diff --git a/tools/ioemu/iodev/iodev.h b/tools/ioemu/iodev/iodev.h
new file mode 100644 (file)
index 0000000..3057f6c
--- /dev/null
@@ -0,0 +1,422 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: iodev.h,v 1.37 2003/08/04 16:03:09 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+/* maximum number of emulated devices allowed.  floppy, vga, etc...
+   you can increase this to anything below 256 since an 8-bit handle
+   is used for each device */
+#define BX_MAX_IO_DEVICES 30
+
+/* the last device in the array is the "default" I/O device */
+#define BX_DEFAULT_IO_DEVICE   (BX_MAX_IO_DEVICES-1)
+
+/* number of IRQ lines supported.  In an ISA PC there are two
+   PIC chips cascaded together.  each has 8 IRQ lines, so there
+   should be 16 IRQ's total */
+#define BX_MAX_IRQS 16
+#define BX_NO_IRQ  -1
+
+
+class bx_pit_c;
+class bx_keyb_c;
+class bx_ioapic_c;
+class bx_g2h_c;
+#if BX_IODEBUG_SUPPORT
+class bx_iodebug_c;
+#endif
+
+
+
+typedef Bit32u (*bx_read_handler_t)(void *, Bit32u, unsigned);
+typedef void   (*bx_write_handler_t)(void *, Bit32u, Bit32u, unsigned);
+
+
+#if BX_USE_DEV_SMF
+#  define BX_DEV_SMF  static
+#  define BX_DEV_THIS bx_devices.
+#else
+#  define BX_DEV_SMF
+#  define BX_DEV_THIS this->
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// bx_devmodel_c declaration
+//////////////////////////////////////////////////////////////////////
+
+// This class defines virtual methods that are common to all devices. 
+// Child classes do not need to implement all of them, because in this 
+// definition they are defined as empty, as opposed to being pure 
+// virtual (= 0).
+class BOCHSAPI bx_devmodel_c : public logfunctions {
+  public:
+  virtual ~bx_devmodel_c () {}
+  virtual void init_mem(BX_MEM_C *) {}
+  virtual void init(void) {}
+  virtual void reset(unsigned type) {}
+  virtual void device_load_state () {}
+  virtual void device_save_state () {}
+};
+
+//////////////////////////////////////////////////////////////////////
+// declare stubs for devices
+//////////////////////////////////////////////////////////////////////
+
+#define STUBFUNC(dev,method) \
+   pluginlog->panic("%s called in %s stub. you must not have loaded the %s plugin", #dev, #method, #dev )
+
+class BOCHSAPI bx_keyb_stub_c : public bx_devmodel_c {
+  public:
+  virtual ~bx_keyb_stub_c () {}
+  // stubs for bx_keyb_c methods
+  virtual void mouse_motion(int delta_x, int delta_y, unsigned button_state) {
+    STUBFUNC(keyboard, mouse_motion);
+  }
+  virtual void gen_scancode(Bit32u key) {
+    STUBFUNC(keyboard, gen_scancode);
+  }
+  virtual void paste_bytes(Bit8u *data, Bit32s length) {
+    STUBFUNC(keyboard, paste_bytes);
+  }
+  virtual void paste_delay_changed () {
+    STUBFUNC(keyboard, paste_delay_changed);
+  }
+  virtual void mouse_enabled_changed(bool enabled) {
+    STUBFUNC(keyboard, mouse_enabled_changed);
+  }
+};
+
+class BOCHSAPI bx_hard_drive_stub_c : public bx_devmodel_c {
+  public:
+  virtual void   close_harddrive(void) {
+    STUBFUNC(HD, close_harddrive);
+  }
+  virtual void   init() {
+    STUBFUNC(HD, init);
+  }
+  virtual void   reset(unsigned type) {
+    STUBFUNC(HD, reset);
+  }
+  virtual Bit32u   get_device_handle(Bit8u channel, Bit8u device) {
+    STUBFUNC(HD, get_device_handle); return 0;
+  }
+  virtual Bit32u   get_first_cd_handle(void) {
+    STUBFUNC(HD, get_first_cd_handle); return 0;
+  }
+  virtual unsigned get_cd_media_status(Bit32u handle) {
+    STUBFUNC(HD, get_cd_media_status); return 0;
+  }
+  virtual unsigned set_cd_media_status(Bit32u handle, unsigned status) {
+    STUBFUNC(HD, set_cd_media_status); return 0;
+  }
+  virtual Bit32u virt_read_handler(Bit32u address, unsigned io_len) 
+  {
+    STUBFUNC(HD, virt_read_handler); return 0;
+  }
+  virtual void   virt_write_handler(Bit32u address,
+      Bit32u value, unsigned io_len) 
+  {
+    STUBFUNC(HD, virt_write_handler);
+  }
+};
+
+class BOCHSAPI bx_floppy_stub_c : public bx_devmodel_c {
+  public:
+  virtual unsigned get_media_status(unsigned drive) {
+    STUBFUNC(floppy,  get_media_status); return 0;
+  }
+  virtual unsigned set_media_status(unsigned drive, unsigned status) {
+    STUBFUNC(floppy, set_media_status); return 0;
+  }
+};
+
+class BOCHSAPI bx_cmos_stub_c : public bx_devmodel_c {
+  public:
+  virtual Bit32u get_reg(unsigned reg) {
+    STUBFUNC(cmos, get_reg); return 0;
+  }
+  virtual void set_reg(unsigned reg, Bit32u val) {
+    STUBFUNC(cmos, set_reg);
+  }
+  virtual time_t get_timeval() {
+    // STUBFUNC(cmos, get_timeval); 
+    return 0;
+  }
+  virtual void checksum_cmos(void) {
+    STUBFUNC(cmos, checksum);
+  }
+};
+
+class BOCHSAPI bx_dma_stub_c : public bx_devmodel_c {
+  public:
+  virtual unsigned registerDMA8Channel(
+    unsigned channel,
+    void (* dmaRead)(Bit8u *data_byte),
+    void (* dmaWrite)(Bit8u *data_byte),
+    const char *name
+    ) {
+    STUBFUNC(dma, registerDMA8Channel); return 0;
+  }
+  virtual unsigned registerDMA16Channel(
+    unsigned channel,
+    void (* dmaRead)(Bit16u *data_word),
+    void (* dmaWrite)(Bit16u *data_word),   
+    const char *name
+    ) {
+    STUBFUNC(dma, registerDMA16Channel); return 0;
+  }
+  virtual unsigned unregisterDMAChannel(unsigned channel) {
+    STUBFUNC(dma, unregisterDMAChannel); return 0;
+  }
+  virtual unsigned get_TC(void) {
+    STUBFUNC(dma, get_TC); return 0;
+  }
+  virtual void set_DRQ(unsigned channel, bx_bool val) {
+    STUBFUNC(dma, set_DRQ);
+  }
+  virtual void raise_HLDA(void) {
+    STUBFUNC(dma, raise_HLDA);
+  }
+};
+
+class BOCHSAPI bx_pic_stub_c : public bx_devmodel_c {
+  public:
+  virtual void raise_irq(unsigned irq_no) {
+    STUBFUNC(pic, raise_irq); 
+  }
+  virtual void lower_irq(unsigned irq_no) {
+    STUBFUNC(pic, lower_irq); 
+  }
+  virtual Bit8u IAC(void) {
+    STUBFUNC(pic, IAC); return 0;
+  }
+  virtual void show_pic_state(void) {
+    STUBFUNC(pic, show_pic_state);
+  }
+};
+
+class BOCHSAPI bx_vga_stub_c : public bx_devmodel_c {
+  public:
+  virtual void redraw_area(unsigned x0, unsigned y0, 
+                           unsigned width, unsigned height) {
+    STUBFUNC(vga, redraw_area);  
+  }
+  virtual Bit8u mem_read(Bit32u addr) {
+    STUBFUNC(vga, mem_read);  return 0;
+  }
+  virtual void mem_write(Bit32u addr, Bit8u value) {
+    STUBFUNC(vga, mem_write);
+  }
+  virtual void get_text_snapshot(Bit8u **text_snapshot, 
+                                 unsigned *txHeight, unsigned *txWidth) {
+    STUBFUNC(vga, get_text_snapshot); 
+  }
+  virtual void trigger_timer(void *this_ptr) {
+    STUBFUNC(vga, trigger_timer); 
+  }
+  virtual void set_update_interval (unsigned interval) {
+    STUBFUNC(vga, set_update_interval); 
+  }
+  virtual Bit8u get_actl_palette_idx(Bit8u index) {
+    return 0;
+  }
+};
+
+class BOCHSAPI bx_pci_stub_c : public bx_devmodel_c {
+  public:
+  virtual bx_bool register_pci_handlers(void *this_ptr,
+                                        Bit32u (*bx_pci_read_handler)(void *, Bit8u, unsigned),
+                                        void(*bx_pci_write_handler)(void *, Bit8u, Bit32u, unsigned),
+                                        Bit8u devfunc, const char *name) {
+    STUBFUNC(pci, register_pci_handlers); return 0;
+  }
+  virtual Bit8u rd_memType (Bit32u addr) {
+    return 0;
+  }
+  virtual Bit8u wr_memType (Bit32u addr) {
+    return 0;
+  }
+  virtual void print_i440fx_state(void) {}
+};
+
+class BOCHSAPI bx_ne2k_stub_c : public bx_devmodel_c {
+  public:
+  virtual void print_info(FILE *file, int page, int reg, int nodups) {}
+};
+
+class BOCHSAPI bx_devices_c : public logfunctions {
+public:
+  bx_devices_c(void);
+  ~bx_devices_c(void);
+  // Register I/O addresses and IRQ lines. Initialize any internal
+  // structures.  init() is called only once, even if the simulator
+  // reboots or is restarted.
+  void init(BX_MEM_C *);
+  // Enter reset state in response to a reset condition.
+  // The types of reset conditions are defined in bochs.h:
+  // power-on, hardware, or software.
+  void reset(unsigned type);
+  BX_MEM_C *mem;  // address space associated with these devices
+  bx_bool register_io_read_handler(void *this_ptr, bx_read_handler_t f, Bit32u addr, const char *name, Bit8u mask );
+  bx_bool register_io_write_handler(void *this_ptr, bx_write_handler_t f, Bit32u addr, const char *name, Bit8u mask );
+  bx_bool register_default_io_read_handler(void *this_ptr, bx_read_handler_t f, const char *name, Bit8u mask );
+  bx_bool register_default_io_write_handler(void *this_ptr, bx_write_handler_t f, const char *name, Bit8u mask );
+  bx_bool register_irq(unsigned irq, const char *name);
+  bx_bool unregister_irq(unsigned irq, const char *name);
+  void iodev_init(void);
+  Bit32u inp(Bit16u addr, unsigned io_len) BX_CPP_AttrRegparmN(2);
+  void   outp(Bit16u addr, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
+
+  static void timer_handler(void *);
+  void timer(void);
+
+  bx_devmodel_c    *pluginBiosDevice;
+  bx_ioapic_c      *ioapic;
+  bx_pci_stub_c    *pluginPciBridge;
+  bx_devmodel_c    *pluginPci2IsaBridge;
+  bx_devmodel_c    *pluginPciVgaAdapter;
+  bx_devmodel_c    *pluginPciUSBAdapter;
+  bx_pit_c         *pit;
+  bx_keyb_stub_c   *pluginKeyboard;
+  bx_dma_stub_c    *pluginDmaDevice;
+  bx_floppy_stub_c *pluginFloppyDevice;
+  bx_cmos_stub_c   *pluginCmosDevice;
+  bx_devmodel_c    *pluginSerialDevice;
+  bx_devmodel_c    *pluginParallelDevice;
+  bx_devmodel_c    *pluginUnmapped;
+  bx_vga_stub_c    *pluginVgaDevice;
+  bx_pic_stub_c    *pluginPicDevice;
+  bx_hard_drive_stub_c *pluginHardDrive;
+  bx_devmodel_c    *pluginSB16Device;
+  bx_ne2k_stub_c   *pluginNE2kDevice;
+  bx_g2h_c         *g2h;
+  bx_devmodel_c    *pluginExtFpuIrq;
+  bx_devmodel_c    *pluginGameport;
+#if BX_IODEBUG_SUPPORT
+  bx_iodebug_c    *iodebug;
+#endif
+
+  // stub classes that the pointers (above) can point to until a plugin is
+  // loaded
+  bx_cmos_stub_c stubCmos;
+  bx_keyb_stub_c stubKeyboard;
+  bx_hard_drive_stub_c stubHardDrive;
+  bx_dma_stub_c  stubDma;
+  bx_pic_stub_c  stubPic;
+  bx_floppy_stub_c  stubFloppy;
+  bx_vga_stub_c  stubVga;
+  bx_pci_stub_c  stubPci;
+  bx_ne2k_stub_c stubNE2k;
+
+  // Some info to pass to devices which can handled bulk IO.  This allows
+  // the interface to remain the same for IO devices which can't handle
+  // bulk IO.  We should probably implement special INPBulk() and OUTBulk()
+  // functions which stick these values in the bx_devices_c class, and
+  // then call the normal functions rather than having gross globals
+  // variables.
+  Bit32u   bulkIOHostAddr;
+  unsigned bulkIOQuantumsRequested;
+  unsigned bulkIOQuantumsTransferred;
+
+private:
+
+  Bit8u                 read_handler_id[0x10000];  // 64K
+  struct {
+    bx_read_handler_t funct;
+    void             *this_ptr;
+    const char       *handler_name;  // name of device
+    Bit8u             mask;          // io_len mask
+    } io_read_handler[BX_MAX_IO_DEVICES];
+  unsigned              num_read_handles;
+
+  Bit8u                 write_handler_id[0x10000]; // 64K
+  struct {
+    bx_write_handler_t funct;
+    void              *this_ptr;
+    const char        *handler_name;  // name of device
+    Bit8u              mask;          // io_len mask
+    } io_write_handler[BX_MAX_IO_DEVICES];
+  unsigned              num_write_handles;
+
+  // more for informative purposes, the names of the devices which
+  // are use each of the IRQ 0..15 lines are stored here
+  const char *irq_handler_name[BX_MAX_IRQS];
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  BX_DEV_SMF Bit32u port92_read(Bit32u address, unsigned io_len);
+  BX_DEV_SMF void   port92_write(Bit32u address, Bit32u value, unsigned io_len);
+
+  static Bit32u default_read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+
+  int timer_handle;
+  bx_bool is_serial_enabled ();
+  bx_bool is_usb_enabled ();
+  bx_bool is_parallel_enabled ();
+  };
+
+
+
+#if BX_PCI_SUPPORT
+#include "iodev/pci.h"
+#include "iodev/pci2isa.h"
+#if BX_PCI_VGA_SUPPORT
+#include "iodev/pcivga.h"
+#endif
+#if BX_PCI_USB_SUPPORT
+#include "iodev/pciusb.h"
+#endif
+#endif
+#include "iodev/vga.h"
+#if BX_SUPPORT_APIC
+#  include "iodev/ioapic.h"
+#endif
+#include "iodev/biosdev.h"
+#include "iodev/cmos.h"
+#include "iodev/dma.h"
+#include "iodev/floppy.h"
+#include "iodev/harddrv.h"
+#if BX_IODEBUG_SUPPORT
+#   include "iodev/iodebug.h"
+#endif
+#include "iodev/keyboard.h"
+#include "iodev/parallel.h"
+#include "iodev/pic.h"
+#include "iodev/pit.h"
+#include "iodev/pit_wrap.h"
+#include "iodev/virt_timer.h"
+#include "iodev/serial.h"
+#if BX_SUPPORT_SB16
+#  include "iodev/sb16.h"
+#endif
+#include "iodev/unmapped.h"
+#include "iodev/eth.h"
+#include "iodev/ne2k.h"
+#include "iodev/guest2host.h"
+#include "iodev/slowdown_timer.h"
+#include "iodev/extfpuirq.h"
+#include "iodev/gameport.h"
diff --git a/tools/ioemu/iodev/keyboard.cc b/tools/ioemu/iodev/keyboard.cc
new file mode 100644 (file)
index 0000000..693f4a4
--- /dev/null
@@ -0,0 +1,1611 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keyboard.cc,v 1.82 2003/11/11 18:18:36 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Now features proper implementation of keyboard opcodes 0xF4 to 0xF6
+// Silently ignores PS/2 keyboard extensions (0xF7 to 0xFD)
+// Explicit panic on resend (0xFE)
+//
+// Emmanuel Marty <core@ggi-project.org>
+
+// NB: now the PS/2 mouse support is in, outb changes meaning
+// in conjunction with auxb
+// auxb == 0 && outb == 0  => both buffers empty (nothing to read)
+// auxb == 0 && outb == 1  => keyboard controller output buffer full
+// auxb == 1 && outb == 0  => not used
+// auxb == 1 && outb == 1  => mouse output buffer full.
+// (das)
+
+// Notes from Christophe Bothamy <cbbochs@free.fr>
+//
+// This file includes code from Ludovic Lange (http://ludovic.lange.free.fr)
+// Implementation of 3 scancodes sets mf1,mf2,mf3 with or without translation. 
+// Default is mf2 with translation
+// Ability to switch between scancodes sets
+// Ability to turn translation on or off
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#include <math.h>
+#include "scancodes.h"
+
+#define LOG_THIS  theKeyboard->
+#define VERBOSE_KBD_DEBUG 0
+
+
+bx_keyb_c *theKeyboard = NULL;
+
+  int
+libkeyboard_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  // Create one instance of the keyboard device object.
+  theKeyboard = new bx_keyb_c ();
+  // Before this plugin was loaded, pluginKeyboard pointed to a stub.
+  // Now make it point to the real thing.
+  bx_devices.pluginKeyboard = theKeyboard;
+  // Register this device.
+  BX_REGISTER_DEVICE_DEVMODEL (plugin, type, theKeyboard, BX_PLUGIN_KEYBOARD);
+  return(0); // Success
+}
+
+  void
+libkeyboard_LTX_plugin_fini(void)
+{
+  BX_INFO (("keyboard plugin_fini"));
+}
+
+bx_keyb_c::bx_keyb_c(void)
+{
+  // constructor
+  put("KBD");
+  settype(KBDLOG);
+}
+
+bx_keyb_c::~bx_keyb_c(void)
+{
+  // destructor
+  BX_DEBUG(("Exit."));
+}
+
+
+// flush internal buffer and reset keyboard settings to power-up condition
+  void
+bx_keyb_c::resetinternals(bx_bool powerup)
+{
+  Bit32u   i;
+
+  BX_KEY_THIS s.kbd_internal_buffer.num_elements = 0;
+  for (i=0; i<BX_KBD_ELEMENTS; i++)
+    BX_KEY_THIS s.kbd_internal_buffer.buffer[i] = 0;
+  BX_KEY_THIS s.kbd_internal_buffer.head = 0;
+
+  BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
+
+  // Default scancode set is mf2 with translation
+  BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
+  BX_KEY_THIS s.kbd_controller.current_scancodes_set = 1;
+  BX_KEY_THIS s.kbd_controller.scancodes_translate = 1;
+  
+  if (powerup) {
+    BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
+    BX_KEY_THIS s.kbd_internal_buffer.delay = 1; // 500 mS
+    BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = 0x0b; // 10.9 chars/sec
+    }
+}
+
+
+
+  void
+bx_keyb_c::init(void)
+{
+  BX_DEBUG(("Init $Id: keyboard.cc,v 1.82 2003/11/11 18:18:36 vruppert Exp $"));
+  Bit32u   i;
+
+  DEV_register_irq(1, "8042 Keyboard controller");
+  DEV_register_irq(12, "8042 Keyboard controller (PS/2 mouse)");
+
+  DEV_register_ioread_handler(this, read_handler,
+                                      0x0060, "8042 Keyboard controller", 1);
+  DEV_register_ioread_handler(this, read_handler,
+                                      0x0064, "8042 Keyboard controller", 1);
+  DEV_register_iowrite_handler(this, write_handler,
+                                      0x0060, "8042 Keyboard controller", 1);
+  DEV_register_iowrite_handler(this, write_handler,
+                                      0x0064, "8042 Keyboard controller", 1);
+  BX_KEY_THIS timer_handle = bx_pc_system.register_timer( this, timer_handler,
+                                 bx_options.Okeyboard_serial_delay->get(), 1, 1,
+                                "8042 Keyboard controller");
+
+  resetinternals(1);
+
+  BX_KEY_THIS s.kbd_internal_buffer.led_status = 0;
+  BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+
+  BX_KEY_THIS s.mouse_internal_buffer.num_elements = 0;
+  for (i=0; i<BX_MOUSE_BUFF_SIZE; i++)
+    BX_KEY_THIS s.mouse_internal_buffer.buffer[i] = 0;
+  BX_KEY_THIS s.mouse_internal_buffer.head = 0;
+
+  //  BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+  BX_KEY_THIS s.kbd_controller.pare = 0;
+  BX_KEY_THIS s.kbd_controller.tim  = 0;
+  BX_KEY_THIS s.kbd_controller.auxb = 0;
+  BX_KEY_THIS s.kbd_controller.keyl = 1;
+  BX_KEY_THIS s.kbd_controller.c_d  = 1;
+  BX_KEY_THIS s.kbd_controller.sysf = 0;
+  BX_KEY_THIS s.kbd_controller.inpb = 0;
+  BX_KEY_THIS s.kbd_controller.outb = 0;
+
+  BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
+  BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
+  BX_KEY_THIS s.kbd_controller.allow_irq1 = 1;
+  BX_KEY_THIS s.kbd_controller.allow_irq12 = 1;
+  BX_KEY_THIS s.kbd_controller.kbd_output_buffer = 0;
+  BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
+  BX_KEY_THIS s.kbd_controller.last_comm = 0;
+  BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+  BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+  BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+  BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+
+//BX_DEBUG(( "# Okeyboard_serial_delay is %u usec",
+//        (unsigned) bx_options.Okeyboard_serial_delay->get ()));
+  BX_KEY_THIS s.kbd_controller.timer_pending = 0;
+
+  // Mouse initialization stuff
+  BX_KEY_THIS s.mouse.sample_rate     = 100; // reports per second
+  BX_KEY_THIS s.mouse.resolution_cpmm = 4;   // 4 counts per millimeter
+  BX_KEY_THIS s.mouse.scaling         = 1;   /* 1:1 (default) */
+  BX_KEY_THIS s.mouse.mode            = MOUSE_MODE_RESET;
+  BX_KEY_THIS s.mouse.enable          = 0;
+  BX_KEY_THIS s.mouse.delayed_dx      = 0;
+  BX_KEY_THIS s.mouse.delayed_dy      = 0;
+
+  for (i=0; i<BX_KBD_CONTROLLER_QSIZE; i++)
+    BX_KEY_THIS s.controller_Q[i] = 0;
+  BX_KEY_THIS s.controller_Qsize = 0;
+  BX_KEY_THIS s.controller_Qsource = 0;
+
+  // clear paste buffer
+  BX_KEY_THIS pastebuf = NULL;
+  BX_KEY_THIS pastebuf_len = 0;
+  BX_KEY_THIS pastebuf_ptr = 0;
+  BX_KEY_THIS paste_delay_changed ();
+  BX_KEY_THIS stop_paste = 0;
+
+  // mouse port installed on system board
+  DEV_cmos_set_reg(0x14, DEV_cmos_get_reg(0x14) | 0x04);
+
+#if BX_WITH_WX
+  static bx_bool first_time = 1;
+  if (first_time) {
+    first_time = 0;
+    // register shadow params (Experimental, not a complete list by far)
+    bx_list_c *list = new bx_list_c (BXP_KBD_PARAMETERS, "Keyboard State", "", 20);
+    list->add (new bx_shadow_bool_c (BXP_KBD_IRQ1_REQ, 
+         "Keyboard IRQ1 requested: ", "",
+         &BX_KEY_THIS s.kbd_controller.irq1_requested));
+    list->add (new bx_shadow_bool_c (BXP_KBD_IRQ12_REQ,
+         "Keyboard IRQ12 requested: ", "",
+         &BX_KEY_THIS s.kbd_controller.irq12_requested));
+    list->add (new bx_shadow_num_c (BXP_KBD_TIMER_PENDING,
+       "Keyboard timer pending: ", "",
+       &BX_KEY_THIS s.kbd_controller.timer_pending));
+    list->add (new bx_shadow_bool_c (BXP_KBD_PARE,
+       "Keyboard PARE", "",
+       &BX_KEY_THIS s.kbd_controller.pare));
+    list->add (new bx_shadow_bool_c (BXP_KBD_TIM,
+       "Keyboard TIM", "",
+       &BX_KEY_THIS s.kbd_controller.tim));
+    list->add (new bx_shadow_bool_c (BXP_KBD_AUXB,
+       "Keyboard AUXB", "",
+       &BX_KEY_THIS s.kbd_controller.auxb));
+    list->add (new bx_shadow_bool_c (BXP_KBD_KEYL,
+       "Keyboard KEYL", "",
+       &BX_KEY_THIS s.kbd_controller.keyl));
+    list->add (new bx_shadow_bool_c (BXP_KBD_C_D,
+       "Keyboard C_D", "",
+       &BX_KEY_THIS s.kbd_controller.c_d));
+    list->add (new bx_shadow_bool_c (BXP_KBD_SYSF,
+       "Keyboard SYSF", "",
+       &BX_KEY_THIS s.kbd_controller.sysf));
+    list->add (new bx_shadow_bool_c (BXP_KBD_INPB,
+       "Keyboard INPB", "",
+       &BX_KEY_THIS s.kbd_controller.inpb));
+    list->add (new bx_shadow_bool_c (BXP_KBD_OUTB,
+       "Keyboard OUTB", "",
+       &BX_KEY_THIS s.kbd_controller.outb));
+  }
+#endif
+}
+
+  void
+bx_keyb_c::reset(unsigned type)
+{
+  if (BX_KEY_THIS pastebuf != NULL) {
+    BX_KEY_THIS stop_paste = 1;
+  }
+}
+
+  void
+bx_keyb_c::paste_delay_changed()
+{
+  BX_KEY_THIS pastedelay = bx_options.Okeyboard_paste_delay->get()/BX_IODEV_HANDLER_PERIOD;
+  BX_INFO(("will paste characters every %d keyboard ticks",BX_KEY_THIS pastedelay));
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+// read function - the big picture:
+// if address == data port then
+//    if byte for mouse then return it
+//    else if byte for keyboard then return it
+// else address== status port
+//    assemble the status bits and return them.
+//
+  Bit32u
+bx_keyb_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_KEY_SMF
+  bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_keyb_c::read(Bit32u   address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_KEY_SMF
+
+//BX_DEBUG(( "read from port 0x%04x", (unsigned) address));
+
+  if (address == 0x60) { /* output buffer */
+    Bit8u   val;
+    if (BX_KEY_THIS s.kbd_controller.auxb) { /* mouse byte available */
+      val = BX_KEY_THIS s.kbd_controller.aux_output_buffer;
+      BX_KEY_THIS s.kbd_controller.aux_output_buffer = 0;
+      //      BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+      BX_KEY_THIS s.kbd_controller.outb = 0;
+      BX_KEY_THIS s.kbd_controller.auxb = 0;
+      BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+
+      if (BX_KEY_THIS s.controller_Qsize) {
+        unsigned i;
+        BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
+       //      BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+        BX_KEY_THIS s.kbd_controller.outb = 1;
+        BX_KEY_THIS s.kbd_controller.auxb = 1;
+        if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+          BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+        for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
+          // move Q elements towards head of queue by one
+          BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
+          }
+        BX_KEY_THIS s.controller_Qsize--;
+        }
+
+//BX_DEBUG(("mouse: ___io_read aux = 0x%02x", (unsigned) val));
+
+      DEV_pic_lower_irq(12);
+      activate_timer();
+      BX_DEBUG(("READ(%02x) (from mouse) = %02x", (unsigned) address,
+          (unsigned) val));
+      return val;
+      }
+    else if (BX_KEY_THIS s.kbd_controller.outb) { /* kbd byte available */
+      val = BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+      // BX_INFO(("kbd: %04d outb 0 auxb 0",__LINE__)); // das
+      BX_KEY_THIS s.kbd_controller.outb = 0;
+      BX_KEY_THIS s.kbd_controller.auxb = 0;
+      BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+//BX_DEBUG(( "___io_read kbd"));
+
+      if (BX_KEY_THIS s.controller_Qsize) {
+        unsigned i;
+        BX_KEY_THIS s.kbd_controller.aux_output_buffer = BX_KEY_THIS s.controller_Q[0];
+       //      BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+        BX_KEY_THIS s.kbd_controller.outb = 1;
+        BX_KEY_THIS s.kbd_controller.auxb = 1;
+        if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+          BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+        for (i=0; i<BX_KEY_THIS s.controller_Qsize-1; i++) {
+          // move Q elements towards head of queue by one
+          BX_KEY_THIS s.controller_Q[i] = BX_KEY_THIS s.controller_Q[i+1];
+          }
+       BX_DEBUG(("s.controller_Qsize: %02X",BX_KEY_THIS s.controller_Qsize));
+        BX_KEY_THIS s.controller_Qsize--;
+        }
+
+      DEV_pic_lower_irq(1);
+      activate_timer();
+      BX_DEBUG(("READ(%02x) = %02x", (unsigned) address,
+          (unsigned) val));
+      return val;
+      }
+    else {
+        BX_DEBUG(("num_elements = %d", BX_KEY_THIS s.kbd_internal_buffer.num_elements));
+        BX_DEBUG(("read from port 60h with outb empty"));
+//        val = BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+      return BX_KEY_THIS s.kbd_controller.kbd_output_buffer;
+      }
+    }
+
+#if BX_CPU_LEVEL >= 2
+  else if (address == 0x64) { /* status register */
+
+    return (BX_KEY_THIS s.kbd_controller.pare << 7)  |
+          (BX_KEY_THIS s.kbd_controller.tim  << 6)  |
+          (BX_KEY_THIS s.kbd_controller.auxb << 5)  |
+          (BX_KEY_THIS s.kbd_controller.keyl << 4)  |
+          (BX_KEY_THIS s.kbd_controller.c_d  << 3)  |
+          (BX_KEY_THIS s.kbd_controller.sysf << 2)  |
+          (BX_KEY_THIS s.kbd_controller.inpb << 1)  |
+          BX_KEY_THIS s.kbd_controller.outb;
+    }
+
+#else /* BX_CPU_LEVEL > 0 */
+  /* XT MODE, System 8255 Mode Register */
+  else if (address == 0x64) { /* status register */
+    BX_DEBUG(("IO read from port 64h, system 8255 mode register"));
+    return BX_KEY_THIS s.kbd_controller.outb;
+    }
+#endif /* BX_CPU_LEVEL > 0 */
+
+  BX_PANIC(("unknown address in io read to keyboard port %x",
+      (unsigned) address));
+  return 0; /* keep compiler happy */
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_keyb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_KEY_SMF
+  bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_keyb_c::write( Bit32u   address, Bit32u   value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_KEY_SMF
+  Bit8u   command_byte;
+  static int kbd_initialized=0;
+
+  BX_DEBUG(("keyboard: 8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
+
+  switch (address) {
+    case 0x60: // input buffer
+      // if expecting data byte from command last sent to port 64h
+      if (BX_KEY_THIS s.kbd_controller.expecting_port60h) {
+        BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+        // data byte written last to 0x60
+        BX_KEY_THIS s.kbd_controller.c_d = 0;
+        if (BX_KEY_THIS s.kbd_controller.inpb) {
+          BX_PANIC(("write to port 60h, not ready for write"));
+          }
+        switch (BX_KEY_THIS s.kbd_controller.last_comm) {
+          case 0x60: // write command byte
+            {
+            bx_bool scan_convert, disable_keyboard,
+                    disable_aux;
+
+            scan_convert = (value >> 6) & 0x01;
+            disable_aux      = (value >> 5) & 0x01;
+            disable_keyboard = (value >> 4) & 0x01;
+            BX_KEY_THIS s.kbd_controller.sysf = (value >> 2) & 0x01;
+            BX_KEY_THIS s.kbd_controller.allow_irq1  = (value >> 0) & 0x01;
+            BX_KEY_THIS s.kbd_controller.allow_irq12 = (value >> 1) & 0x01;
+            set_kbd_clock_enable(!disable_keyboard);
+            set_aux_clock_enable(!disable_aux);
+            if (BX_KEY_THIS s.kbd_controller.allow_irq12 && BX_KEY_THIS s.kbd_controller.auxb)
+              BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+            else if (BX_KEY_THIS s.kbd_controller.allow_irq1  && BX_KEY_THIS s.kbd_controller.outb)
+              BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+
+                       BX_DEBUG(( " allow_irq12 set to %u", (unsigned)
+                               BX_KEY_THIS s.kbd_controller.allow_irq12));
+            if ( !scan_convert )
+              BX_ERROR(("keyboard: (mch) scan convert turned off"));
+
+           // (mch) NT needs this
+           BX_KEY_THIS s.kbd_controller.scancodes_translate = scan_convert;
+            }
+            break;
+          case 0xd1: // write output port
+            BX_DEBUG(("write output port with value %02xh",
+                (unsigned) value));
+            BX_SET_ENABLE_A20( (value & 0x02) != 0 );
+            if (!(value & 0x01))
+                               BX_PANIC(("IO write: processor reset requested!"));
+            break;
+          case 0xd4: // Write to mouse
+            // I don't think this enables the AUX clock
+            //set_aux_clock_enable(1); // enable aux clock line
+            kbd_ctrl_to_mouse(value);
+            // ??? should I reset to previous value of aux enable?
+            break;
+
+          case 0xd3: // write mouse output buffer
+            // Queue in mouse output buffer
+            controller_enQ(value, 1);
+            break;
+
+         case 0xd2:
+           // Queue in keyboard output buffer
+           controller_enQ(value, 0);
+           break;
+
+          default:
+            BX_PANIC(("=== unsupported write to port 60h(lastcomm=%02x): %02x",
+              (unsigned) BX_KEY_THIS s.kbd_controller.last_comm, (unsigned) value));
+          }
+        }
+      else {
+        // data byte written last to 0x60
+        BX_KEY_THIS s.kbd_controller.c_d = 0;
+        BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+        /* pass byte to keyboard */
+        /* ??? should conditionally pass to mouse device here ??? */
+        if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0) {
+          BX_ERROR(("keyboard disabled & send of byte %02x to kbd",
+            (unsigned) value));
+          }
+        kbd_ctrl_to_kbd(value);
+        }
+      break;
+
+    case 0x64: // control register
+      // command byte written last to 0x64
+      BX_KEY_THIS s.kbd_controller.c_d = 1;
+      BX_KEY_THIS s.kbd_controller.last_comm = value;
+      // most commands NOT expecting port60 write next
+      BX_KEY_THIS s.kbd_controller.expecting_port60h = 0;
+
+      switch (value) {
+        case 0x20: // get keyboard command byte
+          BX_DEBUG(("get keyboard command byte"));
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+                       BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+          command_byte =
+            (BX_KEY_THIS s.kbd_controller.scancodes_translate << 6) |
+            ((!BX_KEY_THIS s.kbd_controller.aux_clock_enabled) << 5) |
+            ((!BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) << 4) |
+            (0 << 3) |
+            (BX_KEY_THIS s.kbd_controller.sysf << 2) |
+            (BX_KEY_THIS s.kbd_controller.allow_irq12 << 1) |
+            (BX_KEY_THIS s.kbd_controller.allow_irq1  << 0);
+          controller_enQ(command_byte, 0);
+          break;
+        case 0x60: // write command byte
+          BX_DEBUG(("write command byte"));
+          // following byte written to port 60h is command byte
+          BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+          break;
+
+        case 0xa0:
+          BX_DEBUG(("keyboard BIOS name not supported"));
+          break;
+
+        case 0xa1:
+          BX_DEBUG(("keyboard BIOS version not supported"));
+          break;
+
+        case 0xa7: // disable the aux device
+          set_aux_clock_enable(0);
+          BX_DEBUG(("aux device disabled"));
+          break;
+        case 0xa8: // enable the aux device
+          set_aux_clock_enable(1);
+          BX_DEBUG(("aux device enabled"));
+          break;
+        case 0xa9: // Test Mouse Port
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+                       BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+          controller_enQ(0x00, 0); // no errors detected
+          break;
+        case 0xaa: // motherboard controller self test
+          BX_DEBUG(("Self Test"));
+         if( kbd_initialized == 0 )
+         {
+           BX_KEY_THIS s.controller_Qsize = 0;
+           BX_KEY_THIS s.kbd_controller.outb = 0;
+           kbd_initialized++;
+         }
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+               BX_ERROR(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+         // (mch) Why is this commented out??? Enabling
+          BX_KEY_THIS s.kbd_controller.sysf = 1; // self test complete
+          controller_enQ(0x55, 0); // controller OK
+          break;
+        case 0xab: // Interface Test
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+          controller_enQ(0x00, 0);
+          break;
+        case 0xad: // disable keyboard
+          set_kbd_clock_enable(0);
+          BX_DEBUG(("keyboard disabled"));
+          break;
+        case 0xae: // enable keyboard
+          set_kbd_clock_enable(1);
+          BX_DEBUG(("keyboard enabled"));
+          break;
+        case 0xc0: // read input port
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+          // keyboard power normal
+          controller_enQ(0x00, 0);
+          break;
+        case 0xd0: // read output port: next byte read from port 60h
+          BX_DEBUG(("io write to port 64h, command d0h (partial)"));
+          // controller output buffer must be empty
+          if (BX_KEY_THIS s.kbd_controller.outb) {
+BX_PANIC(("kbd: OUTB set and command 0x%02x encountered", value));
+            break;
+            }
+          controller_enQ(
+              (BX_KEY_THIS s.kbd_controller.auxb << 5) |
+              (BX_KEY_THIS s.kbd_controller.outb << 4) |
+              (BX_GET_ENABLE_A20() << 1) |
+              0x01, 0);
+          break;
+
+        case 0xd1: // write output port: next byte written to port 60h
+          BX_DEBUG(("write output port"));
+          // following byte to port 60h written to output port
+          BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+          break;
+
+        case 0xd3: // write mouse output buffer
+         //FIXME: Why was this a panic?
+          BX_DEBUG(("io write 0x64: command = 0xD3(write mouse outb)"));
+         // following byte to port 60h written to output port as mouse write.
+          BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+          break;
+
+        case 0xd4: // write to mouse
+          BX_DEBUG(("io write 0x64: command = 0xD4 (write to mouse)"));
+          // following byte written to port 60h
+          BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+          break;
+
+        case 0xd2: // write keyboard output buffer
+         BX_DEBUG(("io write 0x64: write keyboard output buffer"));
+         BX_KEY_THIS s.kbd_controller.expecting_port60h = 1;
+         break;
+        case 0xdd: // Disable A20 Address Line
+         BX_SET_ENABLE_A20(0);
+         break;
+        case 0xdf: // Enable A20 Address Line
+         BX_SET_ENABLE_A20(1);
+         break;
+        case 0xc1: // Continuous Input Port Poll, Low
+        case 0xc2: // Continuous Input Port Poll, High
+        case 0xe0: // Read Test Inputs
+          BX_PANIC(("io write 0x64: command = %02xh", (unsigned) value));
+          break;
+
+        case 0xfe: // System Reset, transition to real mode
+          BX_INFO(("system reset"));
+          bx_pc_system.ResetSignal( PCS_SET ); /* XXX is this right? */
+         {
+         for (int i=0; i<BX_SMP_PROCESSORS; i++) 
+            BX_CPU(i)->reset(BX_RESET_HARDWARE);
+         }
+          // Use bx_pc_system if necessary bx_cpu.reset_cpu();
+          // bx_pc_system.ResetSignal( PCS_SET );
+          break;
+
+        default:
+          if (value==0xff || (value>=0xf0 && value<=0xfd)) {
+            /* useless pulse output bit commands ??? */
+            BX_DEBUG(("io write to port 64h, useless command %02x",
+                (unsigned) value));
+            return;
+           }
+          BX_PANIC(("unsupported io write to keyboard port %x, value = %x",
+            (unsigned) address, (unsigned) value));
+          break;
+        }
+      break;
+
+    default: BX_PANIC(("unknown address in bx_keyb_c::write()"));
+    }
+}
+
+// service_paste_buf() transfers data from the paste buffer to the hardware
+// keyboard buffer.  It tries to transfer as many chars as possible at a
+// time, but because different chars require different numbers of scancodes
+// we have to be conservative.  Note that this process depends on the
+// keymap tables to know what chars correspond to what keys, and which
+// chars require a shift or other modifier.
+void 
+bx_keyb_c::service_paste_buf ()
+{
+  if (!BX_KEY_THIS pastebuf) return;
+  BX_DEBUG (("service_paste_buf: ptr at %d out of %d", BX_KEY_THIS pastebuf_ptr, BX_KEY_THIS pastebuf_len));
+  int fill_threshold = BX_KBD_ELEMENTS - 8;
+  while ( (BX_KEY_THIS pastebuf_ptr < BX_KEY_THIS pastebuf_len) && ! BX_KEY_THIS stop_paste) {
+    if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= fill_threshold)
+      return;
+    // there room in the buffer for a keypress and a key release.
+    // send one keypress and a key release.
+    Bit8u byte = BX_KEY_THIS pastebuf[BX_KEY_THIS pastebuf_ptr];
+    BXKeyEntry *entry = bx_keymap.findAsciiChar (byte);
+    if (!entry) {
+      BX_ERROR (("paste character 0x%02x ignored", byte));
+    } else {
+      BX_DEBUG (("pasting character 0x%02x. baseKey is %04x", byte, entry->baseKey));
+      if (entry->modKey != BX_KEYMAP_UNKNOWN)
+        BX_KEY_THIS gen_scancode (entry->modKey);
+      BX_KEY_THIS gen_scancode (entry->baseKey);
+      BX_KEY_THIS gen_scancode (entry->baseKey | BX_KEY_RELEASED);
+      if (entry->modKey != BX_KEYMAP_UNKNOWN)
+        BX_KEY_THIS gen_scancode (entry->modKey | BX_KEY_RELEASED);
+    }
+    BX_KEY_THIS pastebuf_ptr++;
+  }
+  // reached end of pastebuf.  free the memory it was using.
+  delete [] BX_KEY_THIS pastebuf;
+  BX_KEY_THIS pastebuf = NULL;
+  BX_KEY_THIS stop_paste = 0;
+}
+
+// paste_bytes schedules an arbitrary number of ASCII characters to be
+// inserted into the hardware queue as it become available.  Any previous
+// paste which is still in progress will be thrown out.  BYTES is a pointer
+// to a region of memory containing the chars to be pasted. When the paste
+// is complete, the keyboard code will call delete [] bytes;
+void
+bx_keyb_c::paste_bytes (Bit8u *bytes, Bit32s length)
+{
+  BX_DEBUG (("paste_bytes: %d bytes", length));
+  if (BX_KEY_THIS pastebuf) {
+    BX_ERROR (("previous paste was not completed!  %d chars lost", 
+         BX_KEY_THIS pastebuf_len - BX_KEY_THIS pastebuf_ptr));
+    delete [] BX_KEY_THIS pastebuf;  // free the old paste buffer
+  }
+  BX_KEY_THIS pastebuf = bytes;
+  BX_KEY_THIS pastebuf_ptr = 0;
+  BX_KEY_THIS pastebuf_len = length;
+  BX_KEY_THIS service_paste_buf ();
+}
+
+  void
+bx_keyb_c::gen_scancode(Bit32u key)
+{
+  unsigned char *scancode;
+  Bit8u  i;
+
+  BX_DEBUG(( "gen_scancode(): %s %s", bx_keymap.getBXKeyName(key), (key >> 31)?"released":"pressed"));
+
+  if (!BX_KEY_THIS s.kbd_controller.scancodes_translate)
+       BX_DEBUG(("keyboard: gen_scancode with scancode_translate cleared"));
+
+  // Ignore scancode if keyboard clock is driven low
+  if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled==0)
+    return;
+
+  // Ignore scancode if scanning is disabled
+  if (BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled==0)
+    return;
+
+  // Switch between make and break code
+  if (key & BX_KEY_RELEASED)
+    scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].brek;
+  else
+    scancode=(unsigned char *)scancodes[(key&0xFF)][BX_KEY_THIS s.kbd_controller.current_scancodes_set].make;
+
+  if (BX_KEY_THIS s.kbd_controller.scancodes_translate) {
+    // Translate before send
+    Bit8u escaped=0x00;
+
+    for (i=0; i<strlen( (const char *)scancode ); i++) {
+      if (scancode[i] == 0xF0)
+        escaped=0x80;
+      else {
+       BX_DEBUG(("gen_scancode(): writing translated %02x",translation8042[scancode[i] ] | escaped));
+        kbd_enQ(translation8042[scancode[i] ] | escaped );
+        escaped=0x00;
+      }
+    }
+  } 
+  else {
+    // Send raw data
+    for (i=0; i<strlen( (const char *)scancode ); i++) {
+      BX_DEBUG(("gen_scancode(): writing raw %02x",scancode[i]));
+      kbd_enQ( scancode[i] );
+    }
+  }
+}
+
+
+
+  void BX_CPP_AttrRegparmN(1)
+bx_keyb_c::set_kbd_clock_enable(Bit8u   value)
+{
+  bx_bool prev_kbd_clock_enabled;
+
+  if (value==0) {
+    BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 0;
+    }
+  else {
+    /* is another byte waiting to be sent from the keyboard ? */
+    prev_kbd_clock_enabled = BX_KEY_THIS s.kbd_controller.kbd_clock_enabled;
+    BX_KEY_THIS s.kbd_controller.kbd_clock_enabled = 1;
+
+    if (prev_kbd_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0) {
+      activate_timer();
+      }
+    }
+}
+
+
+
+  void
+bx_keyb_c::set_aux_clock_enable(Bit8u   value)
+{
+  bx_bool prev_aux_clock_enabled;
+
+  BX_DEBUG(("set_aux_clock_enable(%u)", (unsigned) value));
+  if (value==0) {
+    BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 0;
+    }
+  else {
+    /* is another byte waiting to be sent from the keyboard ? */
+    prev_aux_clock_enabled = BX_KEY_THIS s.kbd_controller.aux_clock_enabled;
+    BX_KEY_THIS s.kbd_controller.aux_clock_enabled = 1;
+    if (prev_aux_clock_enabled==0 && BX_KEY_THIS s.kbd_controller.outb==0)
+      activate_timer();
+    }
+}
+
+  Bit8u
+bx_keyb_c::get_kbd_enable(void)
+{
+  BX_DEBUG(("get_kbd_enable(): getting kbd_clock_enabled of: %02x",
+      (unsigned) BX_KEY_THIS s.kbd_controller.kbd_clock_enabled));
+
+  return(BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
+}
+
+  void
+bx_keyb_c::controller_enQ(Bit8u   data, unsigned source)
+{
+  // source is 0 for keyboard, 1 for mouse
+
+  BX_DEBUG(("controller_enQ(%02x) source=%02x", (unsigned) data,source));
+
+  if (BX_KEY_THIS s.kbd_controller.outb)
+    BX_ERROR(("controller_enQ(): OUTB set!"));
+
+  // see if we need to Q this byte from the controller
+  // remember this includes mouse bytes.
+  if (BX_KEY_THIS s.kbd_controller.outb) {
+    if (BX_KEY_THIS s.controller_Qsize >= BX_KBD_CONTROLLER_QSIZE)
+      BX_PANIC(("controller_enq(): controller_Q full!"));
+    BX_KEY_THIS s.controller_Q[BX_KEY_THIS s.controller_Qsize++] = data;
+    BX_KEY_THIS s.controller_Qsource = source;
+    return;
+    }
+
+  // the Q is empty
+  if (source == 0) { // keyboard
+    BX_KEY_THIS s.kbd_controller.kbd_output_buffer = data;
+    //    BX_INFO(("kbd: %04d outb 1 auxb 0",__LINE__)); // das
+    BX_KEY_THIS s.kbd_controller.outb = 1;
+    BX_KEY_THIS s.kbd_controller.auxb = 0;
+    BX_KEY_THIS s.kbd_controller.inpb = 0;
+    if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+      BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+    }
+  else { // mouse
+    BX_KEY_THIS s.kbd_controller.aux_output_buffer = data;
+    //    BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); // das
+    BX_KEY_THIS s.kbd_controller.outb = 1;
+    BX_KEY_THIS s.kbd_controller.auxb = 1;
+    BX_KEY_THIS s.kbd_controller.inpb = 0;
+    if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+      BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+    }
+}
+
+void
+bx_keyb_c::kbd_enQ_imm(Bit8u val)
+{
+      int tail;
+
+      if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
+           BX_PANIC(("internal keyboard buffer full (imm)"));
+           return;
+      }
+
+      /* enqueue scancode in multibyte internal keyboard buffer */
+      tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
+           BX_KBD_ELEMENTS;
+
+      BX_KEY_THIS s.kbd_controller.kbd_output_buffer = val;
+      //      BX_INFO(("kbd: %04d outb 1",__LINE__)); // das
+      BX_KEY_THIS s.kbd_controller.outb = 1;
+
+      if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+           BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+}
+
+
+  void
+bx_keyb_c::kbd_enQ(Bit8u scancode)
+{
+  int tail;
+
+  BX_DEBUG(("kbd_enQ(0x%02x)", (unsigned) scancode));
+
+  if (BX_KEY_THIS s.kbd_internal_buffer.num_elements >= BX_KBD_ELEMENTS) {
+    BX_INFO(("internal keyboard buffer full, ignoring scancode.(%02x)",
+      (unsigned) scancode));
+    return;
+    }
+
+  /* enqueue scancode in multibyte internal keyboard buffer */
+  BX_DEBUG(("kbd_enQ: putting scancode 0x%02x in internal buffer",
+      (unsigned) scancode));
+  tail = (BX_KEY_THIS s.kbd_internal_buffer.head + BX_KEY_THIS s.kbd_internal_buffer.num_elements) %
+   BX_KBD_ELEMENTS;
+  BX_KEY_THIS s.kbd_internal_buffer.buffer[tail] = scancode;
+  BX_KEY_THIS s.kbd_internal_buffer.num_elements++;
+
+  if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.kbd_clock_enabled) {
+    activate_timer();
+    BX_DEBUG(("activating timer..."));
+    return;
+    }
+//BX_DEBUG(( "# not activating timer...");
+//BX_DEBUG(( "#   allow_irq1 = %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq1);
+//BX_DEBUG(( "#   outb       = %u", (unsigned) BX_KEY_THIS s.kbd_controller.outb);
+//BX_DEBUG(( "#   clock_enab = %u", (unsigned) BX_KEY_THIS s.kbd_controller.kbd_clock_enabled);
+//BX_DEBUG(( "#   out_buffer = %u", (unsigned) BX_KEY_THIS s.kbd_controller.kbd_output_buffer);
+}
+
+  bx_bool BX_CPP_AttrRegparmN(3)
+bx_keyb_c::mouse_enQ_packet(Bit8u   b1, Bit8u   b2, Bit8u   b3)
+{
+  if ((BX_KEY_THIS s.mouse_internal_buffer.num_elements + 3) >= BX_MOUSE_BUFF_SIZE) {
+    return(0); /* buffer doesn't have the space */
+    }
+
+//BX_DEBUG(("mouse: enQ_packet(%02x, %02x, %02x)",
+//  (unsigned) b1, (unsigned) b2, (unsigned) b3));
+
+  mouse_enQ(b1);
+  mouse_enQ(b2);
+  mouse_enQ(b3);
+  return(1);
+}
+
+
+  void
+bx_keyb_c::mouse_enQ(Bit8u   mouse_data)
+{
+  int tail;
+
+  BX_DEBUG(("mouse_enQ(%02x)", (unsigned) mouse_data));
+
+  if (BX_KEY_THIS s.mouse_internal_buffer.num_elements >= BX_MOUSE_BUFF_SIZE) {
+    BX_ERROR(("mouse: internal mouse buffer full, ignoring mouse data.(%02x)",
+      (unsigned) mouse_data));
+    return;
+    }
+//BX_DEBUG(( "# mouse_enq() aux_clock_enabled = %u",
+//  (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled);
+
+  /* enqueue mouse data in multibyte internal mouse buffer */
+  tail = (BX_KEY_THIS s.mouse_internal_buffer.head + BX_KEY_THIS s.mouse_internal_buffer.num_elements) %
+   BX_MOUSE_BUFF_SIZE;
+  BX_KEY_THIS s.mouse_internal_buffer.buffer[tail] = mouse_data;
+  BX_KEY_THIS s.mouse_internal_buffer.num_elements++;
+
+  if (!BX_KEY_THIS s.kbd_controller.outb && BX_KEY_THIS s.kbd_controller.aux_clock_enabled) {
+    activate_timer();
+//BX_DEBUG(( "# activating timer...");
+    return;
+    }
+//BX_DEBUG(( "# not activating timer...");
+//BX_DEBUG(( "#   allow_irq12= %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12);
+//BX_DEBUG(( "#   outb       = %u", (unsigned) BX_KEY_THIS s.kbd_controller.outb);
+//BX_DEBUG(( "#   clock_enab = %u", (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled);
+//BX_DEBUG(( "#   out_buffer = %u", (unsigned) BX_KEY_THIS s.kbd_controller.aux_output_buffer);
+}
+
+  void
+bx_keyb_c::kbd_ctrl_to_kbd(Bit8u   value)
+{
+
+  BX_DEBUG(("controller passed byte %02xh to keyboard", value));
+
+  if (BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic) {
+    BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 0;
+    BX_KEY_THIS s.kbd_internal_buffer.delay = (value >> 5) & 0x03;
+    switch (BX_KEY_THIS s.kbd_internal_buffer.delay) {
+      case 0: BX_INFO(("setting delay to 250 mS (unused)")); break;
+      case 1: BX_INFO(("setting delay to 500 mS (unused)")); break;
+      case 2: BX_INFO(("setting delay to 750 mS (unused)")); break;
+      case 3: BX_INFO(("setting delay to 1000 mS (unused)")); break;
+      }
+    BX_KEY_THIS s.kbd_internal_buffer.repeat_rate = value & 0x1f;
+    double cps = 1 /((double)(8 + (value & 0x07)) * (double)exp(log((double)2) * (double)((value >> 3) & 0x03)) * 0.00417);
+    BX_INFO(("setting repeat rate to %.1f cps (unused)", cps));
+    kbd_enQ(0xFA); // send ACK
+    return;
+    }
+
+  if (BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write) {
+    BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 0;
+    BX_KEY_THIS s.kbd_internal_buffer.led_status = value;
+    BX_DEBUG(("LED status set to %02x",
+      (unsigned) BX_KEY_THIS s.kbd_internal_buffer.led_status));
+    kbd_enQ(0xFA); // send ACK %%%
+    return;
+    }
+
+  if (BX_KEY_THIS s.kbd_controller.expecting_scancodes_set) {
+    BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 0;
+    if( value != 0 ) {
+      if( value<4 ) {
+        BX_KEY_THIS s.kbd_controller.current_scancodes_set = (value-1);
+        BX_INFO(("Switched to scancode set %d\n",
+          (unsigned) BX_KEY_THIS s.kbd_controller.current_scancodes_set + 1));
+        kbd_enQ(0xFA);
+        } 
+      else {
+        BX_ERROR(("Received scancodes set out of range: %d\n", value ));
+        kbd_enQ(0xFF); // send ERROR
+        }
+      } 
+    else {
+      // Send current scancodes set to port 0x60
+      kbd_enQ( 1 + (BX_KEY_THIS s.kbd_controller.current_scancodes_set) ); 
+      }
+    return;
+    }
+
+  switch (value) {
+    case 0x00: // ??? ignore and let OS timeout with no response
+      kbd_enQ(0xFA); // send ACK %%%
+      return;
+      break;
+
+    case 0x05: // ???
+         // (mch) trying to get this to work...
+          BX_KEY_THIS s.kbd_controller.sysf = 1;
+         kbd_enQ_imm(0xfe);
+      return;
+      break;
+
+    case 0xed: // LED Write
+      BX_KEY_THIS s.kbd_internal_buffer.expecting_led_write = 1;
+      kbd_enQ_imm(0xFA); // send ACK %%%
+      return;
+      break;
+
+    case 0xee: // echo
+      kbd_enQ(0xEE); // return same byte (EEh) as echo diagnostic
+      return;
+      break;
+
+    case 0xf0: // Select alternate scan code set
+      BX_KEY_THIS s.kbd_controller.expecting_scancodes_set = 1;
+      BX_DEBUG(("Expecting scancode set info...\n"));
+      kbd_enQ(0xFA); // send ACK
+      return;
+      break;
+
+    case 0xf2:  // identify keyboard
+      BX_INFO(("identify keyboard command received"));
+
+      // XT sends nothing, AT sends ACK 
+      // MFII with translation sends ACK+ABh+41h
+      // MFII without translation sends ACK+ABh+83h
+      if (bx_options.Okeyboard_type->get() != BX_KBD_XT_TYPE) {
+        kbd_enQ(0xFA); 
+        if (bx_options.Okeyboard_type->get() == BX_KBD_MF_TYPE) {
+          kbd_enQ(0xAB);
+          
+          if(BX_KEY_THIS s.kbd_controller.scancodes_translate)
+            kbd_enQ(0x41);
+          else
+            kbd_enQ(0x83);
+          }
+        }
+      return;
+      break;
+
+    case 0xf3:  // typematic info
+      BX_KEY_THIS s.kbd_internal_buffer.expecting_typematic = 1;
+      BX_INFO(("setting typematic info"));
+      kbd_enQ(0xFA); // send ACK
+      return;
+      break;
+
+    case 0xf4:  // enable keyboard
+      BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+      kbd_enQ(0xFA); // send ACK
+      return;
+      break;
+
+    case 0xf5:  // reset keyboard to power-up settings and disable scanning
+      resetinternals(1);
+      kbd_enQ(0xFA); // send ACK
+      BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 0;
+      BX_INFO(("reset-disable command received"));
+      return;
+      break;
+
+    case 0xf6:  // reset keyboard to power-up settings and enable scanning
+      resetinternals(1);
+      kbd_enQ(0xFA); // send ACK
+      BX_KEY_THIS s.kbd_internal_buffer.scanning_enabled = 1;
+      BX_INFO(("reset-enable command received"));
+      return;
+      break;
+
+    case 0xf7:  // PS/2 Set All Keys To Typematic
+    case 0xf8:  // PS/2 Set All Keys to Make/Break
+    case 0xf9:  // PS/2 PS/2 Set All Keys to Make
+    case 0xfa:  // PS/2 Set All Keys to Typematic Make/Break
+    case 0xfb:  // PS/2 Set Key Type to Typematic
+    case 0xfc:  // PS/2 Set Key Type to Make/Break
+    case 0xfd:  // PS/2 Set Key Type to Make
+      // Silently ignore and let the OS timeout, for now.
+      // If anyone has code around that makes use of that, I can
+      // provide documentation on their behavior (ask core@ggi-project.org)
+      return;
+      break;
+
+    case 0xfe:  // resend. aiiee.
+      BX_PANIC( ("got 0xFE (resend)"));
+      return;
+      break;
+
+    case 0xff:  // reset: internal keyboard reset and afterwards the BAT
+      BX_DEBUG(("reset command received"));
+      resetinternals(1);
+      kbd_enQ(0xFA); // send ACK
+      kbd_enQ(0xAA); // BAT test passed
+      return;
+      break;
+
+    case 0xd3:
+      kbd_enQ(0xfa);
+      return;
+
+    default:
+                       /* XXX fix this properly:
+                       http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/mouse/mouse.html
+                       http://sourceforge.net/tracker/index.php?func=detail&aid=422457&group_id=12580&atid=112580
+                        */
+      BX_ERROR(("kbd_ctrl_to_kbd(): got value of %02x",
+        (unsigned) value));
+      kbd_enQ(0xFA); /* send ACK ??? */
+      return;
+      break;
+    }
+}
+
+  void
+bx_keyb_c::timer_handler(void *this_ptr)
+{
+  bx_keyb_c *class_ptr = (bx_keyb_c *) this_ptr;
+  unsigned retval;
+
+  // retval=class_ptr->periodic( bx_options.Okeyboard_serial_delay->get());
+  retval=class_ptr->periodic(1);
+
+  if(retval&0x01)
+    DEV_pic_raise_irq(1);
+  if(retval&0x02)
+    DEV_pic_raise_irq(12);
+}
+
+  unsigned
+bx_keyb_c::periodic( Bit32u   usec_delta )
+{
+/*  static int multiple=0; */
+  static unsigned count_before_paste=0;
+  Bit8u   retval;
+
+  UNUSED( usec_delta );
+
+  if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled ) {
+    if(++count_before_paste>=BX_KEY_THIS pastedelay) {
+      // after the paste delay, consider adding moving more chars
+      // from the paste buffer to the keyboard buffer.
+      BX_KEY_THIS service_paste_buf ();
+      count_before_paste=0;
+    }
+  }
+
+  retval = BX_KEY_THIS s.kbd_controller.irq1_requested | (BX_KEY_THIS s.kbd_controller.irq12_requested << 1);
+  BX_KEY_THIS s.kbd_controller.irq1_requested = 0;
+  BX_KEY_THIS s.kbd_controller.irq12_requested = 0;
+
+  if ( BX_KEY_THIS s.kbd_controller.timer_pending == 0 ) {
+    return(retval);
+    }
+
+  if ( usec_delta >= BX_KEY_THIS s.kbd_controller.timer_pending ) {
+    BX_KEY_THIS s.kbd_controller.timer_pending = 0;
+    }
+  else {
+    BX_KEY_THIS s.kbd_controller.timer_pending -= usec_delta;
+    return(retval);
+    }
+
+  if (BX_KEY_THIS s.kbd_controller.outb) {
+    return(retval);
+    }
+
+  /* nothing in outb, look for possible data xfer from keyboard or mouse */
+  if (BX_KEY_THIS s.kbd_controller.kbd_clock_enabled && BX_KEY_THIS s.kbd_internal_buffer.num_elements) {
+//BX_DEBUG(( "#   servicing keyboard code");
+    BX_DEBUG(("service_keyboard: key in internal buffer waiting"));
+    BX_KEY_THIS s.kbd_controller.kbd_output_buffer =
+      BX_KEY_THIS s.kbd_internal_buffer.buffer[BX_KEY_THIS s.kbd_internal_buffer.head];
+    //    BX_INFO(("kbd: %04d outb 1",__LINE__)); // das
+    BX_KEY_THIS s.kbd_controller.outb = 1;
+    // commented out since this would override the current state of the
+    // mouse buffer flag - no bug seen - just seems wrong (das)
+    //    BX_KEY_THIS s.kbd_controller.auxb = 0;
+//BX_DEBUG(( "# ___kbd::periodic kbd");
+    BX_KEY_THIS s.kbd_internal_buffer.head = (BX_KEY_THIS s.kbd_internal_buffer.head + 1) %
+      BX_KBD_ELEMENTS;
+    BX_KEY_THIS s.kbd_internal_buffer.num_elements--;
+    if (BX_KEY_THIS s.kbd_controller.allow_irq1)
+      BX_KEY_THIS s.kbd_controller.irq1_requested = 1;
+    }
+  else { 
+    create_mouse_packet(0);
+    if (BX_KEY_THIS s.kbd_controller.aux_clock_enabled && BX_KEY_THIS s.mouse_internal_buffer.num_elements) {
+//BX_DEBUG(( "#   servicing mouse code");
+      BX_DEBUG(("service_keyboard: key(from mouse) in internal buffer waiting"));
+      BX_KEY_THIS s.kbd_controller.aux_output_buffer =
+       BX_KEY_THIS s.mouse_internal_buffer.buffer[BX_KEY_THIS s.mouse_internal_buffer.head];
+
+    //    BX_INFO(("kbd: %04d outb 1 auxb 1",__LINE__)); //das
+      BX_KEY_THIS s.kbd_controller.outb = 1;
+      BX_KEY_THIS s.kbd_controller.auxb = 1;
+//BX_DEBUG(( "# ___kbd:periodic aux");
+      BX_KEY_THIS s.mouse_internal_buffer.head = (BX_KEY_THIS s.mouse_internal_buffer.head + 1) %
+       BX_MOUSE_BUFF_SIZE;
+      BX_KEY_THIS s.mouse_internal_buffer.num_elements--;
+//BX_DEBUG(( "#   allow12 = %u", (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12);
+      if (BX_KEY_THIS s.kbd_controller.allow_irq12)
+       BX_KEY_THIS s.kbd_controller.irq12_requested = 1;
+    }
+    else {
+      BX_DEBUG(("service_keyboard(): no keys waiting"));
+    }
+  }
+  return(retval);
+}
+
+
+
+
+  void
+bx_keyb_c::activate_timer(void)
+{
+  if (BX_KEY_THIS s.kbd_controller.timer_pending == 0) {
+    // BX_KEY_THIS s.kbd_controller.timer_pending = bx_options.Okeyboard_serial_delay->get ();
+    BX_KEY_THIS s.kbd_controller.timer_pending = 1;
+    }
+}
+
+
+  void
+bx_keyb_c::kbd_ctrl_to_mouse(Bit8u   value)
+{
+BX_DEBUG(("MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+BX_DEBUG(("  enable = %u", (unsigned) BX_KEY_THIS s.mouse.enable));
+BX_DEBUG(("  allow_irq12 = %u",
+  (unsigned) BX_KEY_THIS s.kbd_controller.allow_irq12));
+BX_DEBUG(("  aux_clock_enabled = %u",
+  (unsigned) BX_KEY_THIS s.kbd_controller.aux_clock_enabled));
+//BX_DEBUG(( "MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+
+  // an ACK (0xFA) is always the first response to any valid input
+  // received from the system other than Set-Wrap-Mode & Resend-Command
+
+
+ if (BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter) {
+       BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+       switch (BX_KEY_THIS s.kbd_controller.last_mouse_command) {
+            case 0xf3: // Set Mouse Sample Rate
+                  BX_KEY_THIS s.mouse.sample_rate = value;
+                  BX_DEBUG(("[mouse] Sampling rate set: %d Hz", value));
+                  controller_enQ(0xFA, 1); // ack
+                  break;
+
+            case 0xe8: // Set Mouse Resolution
+                  switch (value) {
+                        case 0:
+                              BX_KEY_THIS s.mouse.resolution_cpmm = 1;
+                              break;
+                        case 1:
+                              BX_KEY_THIS s.mouse.resolution_cpmm = 2;
+                              break;
+                        case 2:
+                              BX_KEY_THIS s.mouse.resolution_cpmm = 4;
+                              break;
+                        case 3:
+                              BX_KEY_THIS s.mouse.resolution_cpmm = 8;
+                              break;
+                        default:
+                              BX_PANIC(("[mouse] Unknown resolution %d", value));
+                              break;
+                  }
+                  BX_DEBUG(("[mouse] Resolution set to %d counts per mm",
+                                  BX_KEY_THIS s.mouse.resolution_cpmm));
+
+                  controller_enQ(0xFA, 1); // ack
+                  break;
+
+            default:
+                  BX_PANIC(("MOUSE: unknown last command (%02xh)", (unsigned) BX_KEY_THIS s.kbd_controller.last_mouse_command));
+       }
+ } else {
+  BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 0;
+  BX_KEY_THIS s.kbd_controller.last_mouse_command = value;
+
+  // test for wrap mode first
+  if (BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
+    // if not a reset command or reset wrap mode
+    // then just echo the byte.
+    if ((value != 0xff) && (value != 0xec)) {
+      if (bx_dbg.mouse)
+       BX_INFO(("[mouse] wrap mode: Ignoring command %0X02.",value));
+      controller_enQ(value,1);
+      // bail out
+      return;
+    }
+  }
+  switch ( value ) {
+    case 0xe6: // Set Mouse Scaling to 1:1
+      controller_enQ(0xFA, 1); // ACK
+      BX_KEY_THIS s.mouse.scaling         = 2;
+         BX_DEBUG(("[mouse] Scaling set to 1:1"));
+      break;
+
+    case 0xe7: // Set Mouse Scaling to 2:1
+      controller_enQ(0xFA, 1); // ACK
+      BX_KEY_THIS s.mouse.scaling         = 2;
+         BX_DEBUG(("[mouse] Scaling set to 2:1"));
+      break;
+
+    case 0xe8: // Set Mouse Resolution
+      controller_enQ(0xFA, 1); // ACK
+      BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
+      break;
+
+    case 0xea: // Set Stream Mode
+      if (bx_dbg.mouse)
+       BX_INFO(("[mouse] Mouse stream mode on."));
+      BX_KEY_THIS s.mouse.mode = MOUSE_MODE_STREAM;
+      controller_enQ(0xFA, 1); // ACK
+      break;
+
+    case 0xec: // Reset Wrap Mode
+      // unless we are in wrap mode ignore the command
+      if ( BX_KEY_THIS s.mouse.mode == MOUSE_MODE_WRAP) {
+       if (bx_dbg.mouse)
+         BX_INFO(("[mouse] Mouse wrap mode off."));
+       // restore previous mode except disable stream mode reporting.
+       // ### TODO disabling reporting in stream mode
+       BX_KEY_THIS s.mouse.mode = BX_KEY_THIS s.mouse.saved_mode;
+       controller_enQ(0xFA, 1); // ACK
+      }
+      break;
+    case 0xee: // Set Wrap Mode
+      // ### TODO flush output queue.
+      // ### TODO disable interrupts if in stream mode.
+      if (bx_dbg.mouse)
+           BX_INFO(("[mouse] Mouse wrap mode on."));
+      BX_KEY_THIS s.mouse.saved_mode = BX_KEY_THIS s.mouse.mode;
+      BX_KEY_THIS s.mouse.mode = MOUSE_MODE_WRAP;
+      controller_enQ(0xFA, 1); // ACK
+      break;
+
+    case 0xf0: // Set Remote Mode (polling mode, i.e. not stream mode.)
+      if (bx_dbg.mouse)
+           BX_INFO(("[mouse] Mouse remote mode on."));
+      // ### TODO should we flush/discard/ignore any already queued packets?
+      BX_KEY_THIS s.mouse.mode = MOUSE_MODE_REMOTE;
+      controller_enQ(0xFA, 1); // ACK
+      break;
+
+
+    case 0xf2: // Read Device Type
+      controller_enQ(0xFA, 1); // ACK
+      controller_enQ(0x00, 1); // Device ID
+         BX_DEBUG(("[mouse] Read mouse ID"));
+      break;
+
+    case 0xf3: // Set Mouse Sample Rate (sample rate written to port 60h)
+      controller_enQ(0xFA, 1); // ACK
+      BX_KEY_THIS s.kbd_controller.expecting_mouse_parameter = 1;
+      break;
+
+    case 0xf4: // Enable (in stream mode)
+      BX_KEY_THIS s.mouse.enable = 1;
+      controller_enQ(0xFA, 1); // ACK
+         BX_DEBUG(("[mouse] Mouse enabled (stream mode)"));
+      break;
+
+    case 0xf5: // Disable (in stream mode)
+      BX_KEY_THIS s.mouse.enable = 0;
+      controller_enQ(0xFA, 1); // ACK
+         BX_DEBUG(("[mouse] Mouse disabled (stream mode)"));
+      break;
+
+    case 0xf6: // Set Defaults
+      BX_KEY_THIS s.mouse.sample_rate     = 100; /* reports per second (default) */
+      BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
+      BX_KEY_THIS s.mouse.scaling         = 1;   /* 1:1 (default) */
+      BX_KEY_THIS s.mouse.enable          = 0;
+      BX_KEY_THIS s.mouse.mode            = MOUSE_MODE_STREAM;
+      controller_enQ(0xFA, 1); // ACK
+         BX_DEBUG(("[mouse] Set Defaults"));
+      break;
+
+    case 0xff: // Reset
+      BX_KEY_THIS s.mouse.sample_rate     = 100; /* reports per second (default) */
+      BX_KEY_THIS s.mouse.resolution_cpmm = 4; /* 4 counts per millimeter (default) */
+      BX_KEY_THIS s.mouse.scaling         = 1;   /* 1:1 (default) */
+      BX_KEY_THIS s.mouse.mode            = MOUSE_MODE_RESET;
+      BX_KEY_THIS s.mouse.enable          = 0;
+      /* (mch) NT expects an ack here */
+      controller_enQ(0xFA, 1); // ACK
+      controller_enQ(0xAA, 1); // completion code
+      controller_enQ(0x00, 1); // ID code (normal mouse, wheelmouse has id 0x3)
+         BX_DEBUG(("[mouse] Mouse reset"));
+      break;
+
+    case 0xe9: // Get mouse information
+      // should we ack here? (mch): Yes
+      controller_enQ(0xFA, 1); // ACK
+      controller_enQ(BX_KEY_THIS s.mouse.get_status_byte(), 1); // status
+      controller_enQ(BX_KEY_THIS s.mouse.get_resolution_byte(), 1); // resolution
+      controller_enQ(BX_KEY_THIS s.mouse.sample_rate, 1); // sample rate
+         BX_DEBUG(("[mouse] Get mouse information"));
+      break;
+
+    case 0xeb: // Read Data (send a packet when in Remote Mode)
+      controller_enQ(0xFA, 1); // ACK
+      // perhaps we should be adding some movement here.
+      mouse_enQ_packet( ((BX_KEY_THIS s.mouse.button_status & 0x0f) | 0x08),
+                       0x00, 0x00 ); // bit3 of first byte always set
+      //assumed we really aren't in polling mode, a rather odd assumption.
+      BX_ERROR(("[mouse] Warning: Read Data command partially supported."));
+      break;
+
+    default:
+      //FEh Resend
+      BX_PANIC(("MOUSE: kbd_ctrl_to_mouse(%02xh)", (unsigned) value));
+    }
+ }
+}
+
+void
+bx_keyb_c::create_mouse_packet(bool force_enq) {
+  Bit8u   b1, b2, b3;
+
+  //  BX_DEBUG("Calling create_mouse_packet: force_enq=%d\n",force_enq);
+
+  if(BX_KEY_THIS s.mouse_internal_buffer.num_elements && !force_enq)
+    return;
+
+  //  BX_DEBUG("Got to first milestone: force_enq=%d\n",force_enq);
+
+  Bit16s delta_x = BX_KEY_THIS s.mouse.delayed_dx;
+  Bit16s delta_y = BX_KEY_THIS s.mouse.delayed_dy;
+  Bit8u button_state=BX_KEY_THIS s.mouse.button_status | 0x08;
+
+  if(!force_enq && !delta_x && !delta_y) {
+    return;
+  }
+
+  //  BX_DEBUG("Got to second milestone: delta_x=%d, delta_y=%d\n",delta_x,delta_y);
+
+  if(delta_x>254) delta_x=254;
+  if(delta_x<-254) delta_x=-254;
+  if(delta_y>254) delta_y=254;
+  if(delta_y<-254) delta_y=-254;
+
+  b1 = (button_state & 0x0f) | 0x08; // bit3 always set
+
+  if ( (delta_x>=0) && (delta_x<=255) ) {
+    b2 = (Bit8u) delta_x;
+    BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
+    }
+  else if ( delta_x > 255 ) {
+    b2 = (Bit8u) 0xff;
+    BX_KEY_THIS s.mouse.delayed_dx-=255;
+    }
+  else if ( delta_x >= -256 ) {
+    b2 = (Bit8u) delta_x;
+    b1 |= 0x10;
+    BX_KEY_THIS s.mouse.delayed_dx-=delta_x;
+    }
+  else {
+    b2 = (Bit8u) 0x00;
+    b1 |= 0x10;
+    BX_KEY_THIS s.mouse.delayed_dx+=256;
+    }
+
+  if ( (delta_y>=0) && (delta_y<=255) ) {
+    b3 = (Bit8u) delta_y;
+    BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
+    }
+  else if ( delta_y > 255 ) {
+    b3 = (Bit8u) 0xff;
+    BX_KEY_THIS s.mouse.delayed_dy-=255;
+    }
+  else if ( delta_y >= -256 ) {
+    b3 = (Bit8u) delta_y;
+    b1 |= 0x20;
+    BX_KEY_THIS s.mouse.delayed_dy-=delta_y;
+    }
+  else {
+    b3 = (Bit8u) 0x00;
+    b1 |= 0x20;
+    BX_KEY_THIS s.mouse.delayed_dy+=256;
+    }
+  mouse_enQ_packet(b1, b2, b3);
+}
+
+
+void
+bx_keyb_c::mouse_enabled_changed(bool enabled) {
+  if(s.mouse.delayed_dx || BX_KEY_THIS s.mouse.delayed_dy) {
+    create_mouse_packet(1);
+  }
+  s.mouse.delayed_dx=0;
+  s.mouse.delayed_dy=0;
+  BX_DEBUG(("Keyboard mouse disable called."));
+}
+
+  void
+bx_keyb_c::mouse_motion(int delta_x, int delta_y, unsigned button_state)
+{
+  bool force_enq=0;
+
+  // If mouse events are disabled on the GUI headerbar, don't
+  // generate any mouse data
+  if (bx_options.Omouse_enabled->get () == 0)
+    return;
+
+
+  // don't generate interrupts if we are in remote mode.
+  if ( BX_KEY_THIS s.mouse.mode == MOUSE_MODE_REMOTE)
+    // is there any point in doing any work if we don't act on the result
+    // so go home.
+    return;
+
+
+  // Note: enable only applies in STREAM MODE.
+  if ( BX_KEY_THIS s.mouse.enable==0 )
+    return;
+
+  // scale down the motion
+  if ( (delta_x < -1) || (delta_x > 1) )
+    delta_x /= 2;
+  if ( (delta_y < -1) || (delta_y > 1) )
+    delta_y /= 2;
+
+#ifdef VERBOSE_KBD_DEBUG
+  if (delta_x != 0 || delta_y != 0)
+    BX_DEBUG(("[mouse] Dx=%d Dy=%d", delta_x, delta_y));
+#endif  /* ifdef VERBOSE_KBD_DEBUG */
+
+  if( (delta_x==0) && (delta_y==0) && (BX_KEY_THIS s.mouse.button_status == (button_state & 0x3) ) ) {
+    BX_DEBUG(("Ignoring useless mouse_motion call:\n"));
+    BX_DEBUG(("This should be fixed in the gui code.\n"));
+    return;
+  }
+
+  if(BX_KEY_THIS s.mouse.button_status != (button_state & 0x3)) {
+    force_enq=1;
+  }
+
+  BX_KEY_THIS s.mouse.button_status = button_state & 0x3;
+
+  if(delta_x>255) delta_x=255;
+  if(delta_y>255) delta_y=255;
+  if(delta_x<-256) delta_x=-256;
+  if(delta_y<-256) delta_y=-256;
+
+  BX_KEY_THIS s.mouse.delayed_dx+=delta_x;
+  BX_KEY_THIS s.mouse.delayed_dy+=delta_y;
+
+  if((BX_KEY_THIS s.mouse.delayed_dx>255)||
+     (BX_KEY_THIS s.mouse.delayed_dx<-256)||
+     (BX_KEY_THIS s.mouse.delayed_dy>255)||
+     (BX_KEY_THIS s.mouse.delayed_dy<-256)) {
+    force_enq=1;
+  }
+
+  create_mouse_packet(force_enq);
+}
+
+
+  int
+bx_keyb_c::SaveState( class state_file *fd )
+{
+  fd->write_check ("keyboard start");
+  fd->write (&BX_KEY_THIS s, sizeof (BX_KEY_THIS s));
+  fd->write_check ("keyboard end");
+  return(0);
+}
+
+
+  int
+bx_keyb_c::LoadState( class state_file *fd )
+{
+  fd->read_check ("keyboard start");
+  fd->read (&BX_KEY_THIS s, sizeof (BX_KEY_THIS s));
+  fd->read_check ("keyboard end");
+  return(0);
+}
+
diff --git a/tools/ioemu/iodev/keyboard.h b/tools/ioemu/iodev/keyboard.h
new file mode 100644 (file)
index 0000000..24d9ccf
--- /dev/null
@@ -0,0 +1,234 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: keyboard.h,v 1.22 2003/07/13 19:51:21 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#ifndef _PCKEY_H
+#define _PCKEY_H
+
+
+#define BX_KBD_ELEMENTS 16
+#define BX_MOUSE_BUFF_SIZE 48
+
+// these keywords should only be used in keyboard.cc
+#if BX_USE_KEY_SMF
+#  define BX_KEY_SMF  static
+#  define BX_KEY_THIS theKeyboard->
+#else
+#  define BX_KEY_SMF
+#  define BX_KEY_THIS 
+#endif
+
+#define MOUSE_MODE_RESET  10
+#define MOUSE_MODE_STREAM 11
+#define MOUSE_MODE_REMOTE 12
+#define MOUSE_MODE_WRAP   13
+
+class bx_keyb_c : public bx_keyb_stub_c {
+public:
+  bx_keyb_c(void);
+  ~bx_keyb_c(void);
+  // implement bx_devmodel_c interface
+  virtual void     init(void);
+  virtual void     reset(unsigned type);
+  // override stubs from bx_keyb_stub_c
+  virtual void     gen_scancode(Bit32u key);
+  virtual void     paste_bytes(Bit8u *data, Bit32s length);
+  virtual void     mouse_motion(int delta_x, int delta_y, unsigned button_state);
+
+  // update the paste delay based on bx_options.Okeyboard_paste_delay
+  virtual void     paste_delay_changed ();
+  virtual void     mouse_enabled_changed(bool enabled);
+
+private:
+  BX_KEY_SMF Bit8u    get_kbd_enable(void);
+  BX_KEY_SMF void     service_paste_buf ();
+  BX_KEY_SMF void     create_mouse_packet(bool force_enq);
+  BX_KEY_SMF void     mouse_button(unsigned mouse_state);
+  BX_KEY_SMF int      SaveState( class state_file *fd );
+  BX_KEY_SMF int      LoadState( class state_file *fd );
+  BX_KEY_SMF unsigned periodic( Bit32u   usec_delta );
+
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_KEY_SMF
+  void     write(Bit32u   address, Bit32u   value, unsigned io_len);
+  Bit32u   read(Bit32u   address, unsigned io_len);
+#endif
+
+  struct {
+    struct {
+      /* status bits matching the status port*/
+      bx_bool pare; // Bit7, 1= parity error from keyboard/mouse - ignored.
+      bx_bool tim;  // Bit6, 1= timeout from keyboard - ignored.
+      bx_bool auxb; // Bit5, 1= mouse data waiting for CPU to read.
+      bx_bool keyl; // Bit4, 1= keyswitch in lock position - ignored.
+      bx_bool c_d; /*  Bit3, 1=command to port 64h, 0=data to port 60h */
+      bx_bool sysf; // Bit2,
+      bx_bool inpb; // Bit1,
+      bx_bool outb; // Bit0, 1= keyboard data or mouse data ready for CPU
+                    //       check aux to see which. Or just keyboard
+                    //       data before AT style machines
+
+      /* internal to our version of the keyboard controller */
+      bx_bool kbd_clock_enabled;
+      bx_bool aux_clock_enabled;
+      bx_bool allow_irq1;
+      bx_bool allow_irq12;
+      Bit8u   kbd_output_buffer;
+      Bit8u   aux_output_buffer;
+      Bit8u   last_comm;
+      Bit8u   expecting_port60h;
+      Bit8u   expecting_mouse_parameter;
+      Bit8u   last_mouse_command;
+      Bit32u   timer_pending;
+      bx_bool irq1_requested;
+      bx_bool irq12_requested;
+      bx_bool scancodes_translate;
+      bx_bool expecting_scancodes_set;
+      Bit8u   current_scancodes_set;
+      } kbd_controller;
+
+    struct mouseStruct {
+      Bit8u   sample_rate;
+      Bit8u   resolution_cpmm; // resolution in counts per mm
+      Bit8u   scaling;
+      Bit8u   mode;
+      Bit8u   saved_mode;  // the mode prior to entering wrap mode
+      bx_bool enable;
+
+      Bit8u get_status_byte ()
+       {
+         // top bit is 0 , bit 6 is 1 if remote mode.
+         Bit8u ret = (Bit8u) ((mode == MOUSE_MODE_REMOTE) ? 0x40 : 0);
+         ret |= (enable << 5);
+         ret |= (scaling == 1) ? 0 : (1 << 4);
+         ret |= ((button_status & 0x1) << 2);
+         ret |= ((button_status & 0x2) << 0);
+         return ret;
+       }
+
+      Bit8u get_resolution_byte ()
+       {
+         Bit8u ret = 0;
+
+         switch (resolution_cpmm) {
+         case 1:
+           ret = 0;
+           break;
+
+         case 2:
+           ret = 1;
+           break;
+
+         case 4:
+           ret = 2;
+           break;
+
+         case 8:
+           ret = 3;
+           break;
+
+         default:
+           genlog->panic("mouse: invalid resolution_cpmm");
+         };
+         return ret;
+       }
+
+      Bit8u button_status;
+      Bit16s delayed_dx;
+      Bit16s delayed_dy;
+      } mouse;
+
+    struct {
+      int     num_elements;
+      Bit8u   buffer[BX_KBD_ELEMENTS];
+      int     head;
+      bx_bool expecting_typematic;
+      bx_bool expecting_led_write;
+      Bit8u   delay;
+      Bit8u   repeat_rate;
+      Bit8u   led_status;
+      bx_bool scanning_enabled;
+      } kbd_internal_buffer;
+
+    struct {
+      int     num_elements;
+      Bit8u   buffer[BX_MOUSE_BUFF_SIZE];
+      int     head;
+      } mouse_internal_buffer;
+#define BX_KBD_CONTROLLER_QSIZE 5
+    Bit8u    controller_Q[BX_KBD_CONTROLLER_QSIZE];
+    unsigned controller_Qsize;
+    unsigned controller_Qsource; // 0=keyboard, 1=mouse
+    } s; // State information for saving/loading
+
+  // The paste buffer does NOT exist in the hardware.  It is a bochs
+  // construction that allows the user to "paste" arbitrary length sequences of
+  // keystrokes into the emulated machine.  Since the hardware buffer is only
+  // 16 bytes, a very small amount of data can be added to the hardware buffer
+  // at a time.  The paste buffer keeps track of the bytes that have not yet
+  // been pasted.
+  //
+  // Lifetime of a paste buffer: The paste data comes from the system
+  // clipboard, which must be accessed using platform independent code in the
+  // gui.  Because every gui has its own way of managing the clipboard memory
+  // (in X windows, you're supposed to call Xfree for example), in the platform
+  // specific code we make a copy of the clipboard buffer with 
+  // "new Bit8u[length]".  Then the pointer is passed into
+  // bx_keyb_c::paste_bytes, along with the length.  The gui code never touches
+  // the pastebuf again, and does not free it.  The keyboard code is
+  // responsible for deallocating the paste buffer using delete [] buf.  The
+  // paste buffer is binary data, and it is probably NOT null terminated.  
+  //
+  // Summary: A paste buffer is allocated (new) in the platform-specific gui
+  // code, passed to the keyboard model, and is freed (delete[]) when it is no
+  // longer needed.
+  Bit8u *pastebuf;   // ptr to bytes to be pasted, or NULL if none in progress
+  Bit32u pastebuf_len; // length of pastebuf
+  Bit32u pastebuf_ptr; // ptr to next byte to be added to hw buffer
+  Bit32u pastedelay;   // count before paste
+  bx_bool stop_paste;  // stop the current paste operation on hardware reset
+
+  BX_KEY_SMF void     resetinternals(bx_bool powerup);
+  BX_KEY_SMF void     set_kbd_clock_enable(Bit8u   value) BX_CPP_AttrRegparmN(1);
+  BX_KEY_SMF void     set_aux_clock_enable(Bit8u   value);
+  BX_KEY_SMF void     kbd_ctrl_to_kbd(Bit8u   value);
+  BX_KEY_SMF void     kbd_ctrl_to_mouse(Bit8u   value);
+  BX_KEY_SMF void     kbd_enQ(Bit8u   scancode);
+  BX_KEY_SMF void     kbd_enQ_imm(Bit8u   val);
+  BX_KEY_SMF void     activate_timer(void);
+  BX_KEY_SMF void     controller_enQ(Bit8u   data, unsigned source);
+  BX_KEY_SMF bx_bool  mouse_enQ_packet(Bit8u   b1, Bit8u   b2, Bit8u   b3) BX_CPP_AttrRegparmN(3);
+  BX_KEY_SMF void     mouse_enQ(Bit8u   mouse_data);
+
+  static void   timer_handler(void *);
+  void   timer(void);
+  int    timer_handle;
+  };
+
+
+#endif  // #ifndef _PCKEY_H
diff --git a/tools/ioemu/iodev/load32bitOShack.cc b/tools/ioemu/iodev/load32bitOShack.cc
new file mode 100644 (file)
index 0000000..6a0a490
--- /dev/null
@@ -0,0 +1,322 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: load32bitOShack.cc,v 1.14 2003/08/08 00:05:53 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+#include "bochs.h"
+#define LOG_THIS genlog->
+
+
+
+static void bx_load_linux_hack(void);
+static void bx_load_null_kernel_hack(void);
+static Bit32u bx_load_kernel_image(char *path, Bit32u paddr);
+
+  void
+bx_load32bitOSimagehack(void)
+{
+  // Replay IO from log to initialize IO devices to
+  // a reasonable state needed for the OS.  This is done
+  // in lieu of running the 16-bit BIOS to init things,
+  // since we want to test straight 32bit stuff for
+  // freemware.
+
+#ifndef BX_USE_VMX
+  FILE *fp;
+
+  fp = fopen(bx_options.load32bitOSImage.Oiolog->getptr (), "r");
+
+  if (fp == NULL) {
+    BX_PANIC(("could not open IO init file."));
+    }
+
+  while (1) {
+    unsigned len, op, port, val;
+    int ret;
+    ret = fscanf(fp, "%u %u %x %x\n",
+      &len, &op, &port, &val);
+    if (ret != 4) {
+      BX_PANIC(("could not open IO init file."));
+      }
+    if (op == 0) {
+      // read
+      (void) bx_devices.inp(port, len);
+      }
+    else if (op == 1) {
+      // write
+      bx_devices.outp(port, val, len);
+      }
+    else {
+      BX_PANIC(("bad IO op in init filen"));
+      }
+    if (feof(fp)) break;
+    }
+#endif
+
+  // Invoke proper hack depending on which OS image we're loading
+  switch (bx_options.load32bitOSImage.OwhichOS->get ()) {
+    case Load32bitOSLinux:
+      bx_load_linux_hack();
+      break;
+    case Load32bitOSNullKernel:
+      bx_load_null_kernel_hack();
+      break;
+    default:
+      BX_PANIC(("load32bitOSImage: OS not recognized"));
+    }
+}
+
+struct gdt_entry
+{
+  Bit32u low;
+  Bit32u high;
+};
+struct linux_setup_params
+{
+   /* 0x000 */ Bit8u   orig_x;
+   /* 0x001 */ Bit8u   orig_y;
+   /* 0x002 */ Bit16u  memory_size_std;
+   /* 0x004 */ Bit16u  orig_video_page;
+   /* 0x006 */ Bit8u   orig_video_mode;
+   /* 0x007 */ Bit8u   orig_video_cols;
+   /* 0x008 */ Bit16u  unused1;
+   /* 0x00a */ Bit16u  orig_video_ega_bx;
+   /* 0x00c */ Bit16u  unused2;
+   /* 0x00e */ Bit8u   orig_video_lines;
+   /* 0x00f */ Bit8u   orig_video_isVGA;
+   /* 0x010 */ Bit16u  orig_video_points;
+   /* 0x012 */ Bit8u   pad1[0x40 - 0x12];
+   /* 0x040 */ Bit8u   apm_info[0x80 - 0x40];
+   /* 0x080 */ Bit8u   hd0_info[16];
+   /* 0x090 */ Bit8u   hd1_info[16];
+   /* 0x0a0 */ Bit8u   pad2[0x1e0 - 0xa0];
+   /* 0x1e0 */ Bit32u  memory_size_ext;
+   /* 0x1e4 */ Bit8u   pad3[0x1f1 - 0x1e4];
+   /* 0x1f1 */ Bit8u   setup_sects;
+   /* 0x1f2 */ Bit16u  mount_root_rdonly;
+   /* 0x1f4 */ Bit16u  sys_size;
+   /* 0x1f6 */ Bit16u  swap_dev;
+   /* 0x1f8 */ Bit16u  ramdisk_flags;
+   /* 0x1fa */ Bit16u  vga_mode;
+   /* 0x1fc */ Bit16u  orig_root_dev;
+   /* 0x1fe */ Bit16u  bootsect_magic;
+   /* 0x200 */ Bit8u   pad4[0x210 - 0x200];
+   /* 0x210 */ Bit32u  loader_type;
+   /* 0x214 */ Bit32u  kernel_start;
+   /* 0x218 */ Bit32u  initrd_start;
+   /* 0x21c */ Bit32u  initrd_size;
+   /* 0x220 */ Bit8u   pad5[0x400 - 0x220];
+   /* 0x400 */ struct  gdt_entry gdt[128];
+   /* 0x800 */ Bit8u   commandline[2048];
+};
+
+  static void
+bx_load_linux_setup_params( Bit32u initrd_start, Bit32u initrd_size )
+{
+  BX_MEM_C *mem = BX_MEM(0);
+  struct linux_setup_params *params =
+         (struct linux_setup_params *) &mem->vector[0x00090000];
+
+  memset( params, '\0', sizeof(*params) );
+
+  /* Video settings (standard VGA) */
+  params->orig_x = 0;
+  params->orig_y = 0;
+  params->orig_video_page = 0;
+  params->orig_video_mode = 3;
+  params->orig_video_cols = 80;
+  params->orig_video_lines = 25;
+  params->orig_video_points = 16;
+  params->orig_video_isVGA = 1;
+  params->orig_video_ega_bx = 3;
+
+  /* Memory size (total mem - 1MB, in KB) */
+  params->memory_size_ext = (mem->megabytes - 1) * 1024;
+
+  /* Boot parameters */
+  params->loader_type = 1;
+  params->bootsect_magic = 0xaa55;
+  params->mount_root_rdonly = 0;
+  params->orig_root_dev = 0x0100;
+  params->initrd_start = initrd_start;
+  params->initrd_size  = initrd_size;
+
+  /* Initial GDT */
+  params->gdt[2].high = 0x00cf9a00;
+  params->gdt[2].low  = 0x0000ffff;
+  params->gdt[3].high = 0x00cf9200;
+  params->gdt[3].low  = 0x0000ffff;
+}
+
+  void
+bx_load_linux_hack(void)
+{
+#ifndef BX_USE_VMX
+  Bit32u initrd_start = 0, initrd_size = 0;
+
+  // The RESET function will have been called first.
+  // Set CPU and memory features which are assumed at this point.
+
+  // Load Linux kernel image
+  bx_load_kernel_image( bx_options.load32bitOSImage.Opath->getptr (), 0x100000 );
+
+  // Load initial ramdisk image if requested
+  if ( bx_options.load32bitOSImage.Oinitrd->getptr () )
+  {
+    initrd_start = 0x00800000;  /* FIXME: load at top of memory */
+    initrd_size  = bx_load_kernel_image( bx_options.load32bitOSImage.Oinitrd->getptr (), initrd_start );
+  }
+
+  // Setup Linux startup parameters buffer
+  bx_load_linux_setup_params( initrd_start, initrd_size );
+#endif
+
+  // Enable A20 line
+  BX_SET_ENABLE_A20( 1 );
+
+  // Setup PICs the way Linux likes it
+  BX_OUTP( 0x20, 0x11, 1 );
+  BX_OUTP( 0xA0, 0x11, 1 );
+  BX_OUTP( 0x21, 0x20, 1 );
+  BX_OUTP( 0xA1, 0x28, 1 );
+  BX_OUTP( 0x21, 0x04, 1 );
+  BX_OUTP( 0xA1, 0x02, 1 );
+  BX_OUTP( 0x21, 0x01, 1 );
+  BX_OUTP( 0xA1, 0x01, 1 );
+  BX_OUTP( 0x21, 0xFF, 1 );
+  BX_OUTP( 0xA1, 0xFB, 1 );
+
+#ifndef BX_USE_VMX
+  // Disable interrupts and NMIs
+  BX_CPU(0)->clear_IF ();
+#endif
+
+  BX_OUTP( 0x70, 0x80, 1 );
+
+#ifndef BX_USE_VMX
+  // Enter protected mode
+  // Fixed by george (kyriazis at nvidia.com)
+  // BX_CPU(0)->cr0.pe = 1;
+  // BX_CPU(0)->cr0.val32 |= 0x01;
+
+  BX_CPU(0)->SetCR0(BX_CPU(0)->cr0.val32 | 0x01);
+  // load esi with real_mode
+  BX_CPU(0)->gen_reg[BX_32BIT_REG_ESI].dword.erx = 0x90000; 
+
+  // Set up initial GDT
+  BX_CPU(0)->gdtr.limit = 0x400;
+  BX_CPU(0)->gdtr.base  = 0x00090400;
+
+  // Jump to protected mode entry point
+  BX_CPU(0)->jump_protected( NULL, 0x10, 0x00100000 );
+#endif
+}
+
+  void
+bx_load_null_kernel_hack(void)
+{
+#ifndef BX_USE_VMX
+  // The RESET function will have been called first.
+  // Set CPU and memory features which are assumed at this point.
+
+  bx_load_kernel_image(bx_options.load32bitOSImage.Opath->getptr (), 0x100000);
+
+  // EIP deltas
+  BX_CPU(0)->prev_eip =
+  BX_CPU(0)->dword.eip = 0x00100000;
+
+  // CS deltas
+  BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.base = 0x00000000;
+  BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFFF;
+  BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF;
+  BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.g   = 1; // page gran
+  BX_CPU(0)->sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1; // 32bit
+
+  // DS deltas
+  BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.base = 0x00000000;
+  BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit = 0xFFFFF;
+  BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled = 0xFFFFFFFF;
+  BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.g   = 1; // page gran
+  BX_CPU(0)->sregs[BX_SEG_REG_DS].cache.u.segment.d_b = 1; // 32bit
+
+  // CR0 deltas
+  BX_CPU(0)->cr0.pe = 1; // protected mode
+#endif // BX_USE_VMX
+}
+
+  Bit32u
+bx_load_kernel_image(char *path, Bit32u paddr)
+{
+  struct stat stat_buf;
+  int fd, ret;
+  unsigned long size, offset;
+  Bit32u page_size;
+
+  // read in ROM BIOS image file
+  fd = open(path, O_RDONLY
+#ifdef O_BINARY
+            | O_BINARY
+#endif
+           );
+  if (fd < 0) {
+    BX_INFO(( "load_kernel_image: couldn't open image file '%s'.", path ));
+    BX_EXIT(1);
+    }
+  ret = fstat(fd, &stat_buf);
+  if (ret) {
+    BX_INFO(( "load_kernel_image: couldn't stat image file '%s'.", path ));
+    BX_EXIT(1);
+    }
+
+  size = stat_buf.st_size;
+  page_size = ((Bit32u)size + 0xfff) & ~0xfff;
+
+  BX_MEM_C *mem = BX_MEM(0);
+  if ( (paddr + size) > mem->len ) {
+    BX_INFO(( "load_kernel_image: address range > physical memsize!" ));
+    BX_EXIT(1);
+    }
+
+  offset = 0;
+  while (size > 0) {
+    ret = read(fd, (bx_ptr_t) &mem->vector[paddr + offset], size);
+    if (ret <= 0) {
+      BX_INFO(( "load_kernel_image: read failed on image" ));
+      BX_EXIT(1);
+      }
+    size -= ret;
+    offset += ret;
+    }
+  close(fd);
+  BX_INFO(( "#(%u) load_kernel_image: '%s', size=%u read into memory at %08x",
+          BX_SIM_ID, path,
+          (unsigned) stat_buf.st_size,
+          (unsigned) paddr ));
+
+  return page_size;
+}
diff --git a/tools/ioemu/iodev/logio.cc b/tools/ioemu/iodev/logio.cc
new file mode 100644 (file)
index 0000000..2b79719
--- /dev/null
@@ -0,0 +1,631 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: logio.cc,v 1.42 2003/08/24 10:30:07 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#include "bochs.h"
+#include <assert.h>
+#include "state_file.h"
+
+#if BX_WITH_CARBON
+#include <Carbon/Carbon.h>
+#endif
+
+// Just for the iofunctions
+
+
+int Allocio=0;
+
+void
+iofunctions::flush(void) {
+       if(logfd && magic == MAGIC_LOGNUM) {
+               fflush(logfd);
+       }
+}
+
+void
+iofunctions::init(void) {
+       // iofunctions methods must not be called before this magic
+       // number is set.
+       magic=MAGIC_LOGNUM;
+
+       // sets the default logprefix
+       strcpy(logprefix,"%t%e%d");
+       n_logfn = 0;
+       init_log(stderr);
+       log = new logfunc_t(this);
+       log->put("IO");
+       log->settype(IOLOG);
+       log->ldebug ("Init(log file: '%s').",logfn);
+}
+
+void
+iofunctions::add_logfn (logfunc_t *fn)
+{
+  assert (n_logfn < MAX_LOGFNS);
+  logfn_list[n_logfn++] = fn;
+}
+
+void
+iofunctions::set_log_action (int loglevel, int action)
+{
+  for (int i=0; i<n_logfn; i++)
+    logfn_list[i]->setonoff(loglevel, action);
+}
+
+void
+iofunctions::init_log(const char *fn)
+{
+       assert (magic==MAGIC_LOGNUM);
+       // use newfd/newfn so that we can log the message to the OLD log
+       // file descriptor.
+       FILE *newfd = stderr;
+       char *newfn = "/dev/stderr";
+       if( strcmp( fn, "-" ) != 0 ) {
+               newfd = fopen(fn, "w");
+               if(newfd != NULL) {
+                       newfn = strdup(fn);
+                       log->ldebug ("Opened log file '%s'.", fn );
+               } else {
+                       // in constructor, genlog might not exist yet, so do it the safe way.
+                       log->error("Couldn't open log file: %s, using stderr instead", fn);
+                       newfd = stderr;
+               }
+       }
+       logfd = newfd;
+       logfn = newfn;
+}
+
+void
+iofunctions::init_log(FILE *fs)
+{
+       assert (magic==MAGIC_LOGNUM);
+       logfd = fs;
+
+       if(fs == stderr) {
+               logfn = "/dev/stderr";
+       } else if(fs == stdout) { 
+               logfn = "/dev/stdout";
+       } else {
+               logfn = "(unknown)";
+       }
+
+}
+
+void
+iofunctions::init_log(int fd)
+{
+       assert (magic==MAGIC_LOGNUM);
+       FILE *tmpfd;
+       if( (tmpfd = fdopen(fd,"w")) == NULL ) {
+         log->panic("Couldn't open fd %d as a stream for writing", fd);
+         return;
+       }
+
+       init_log(tmpfd);
+       return;
+};
+
+// all other functions may use genlog safely.
+#define LOG_THIS genlog->
+
+// This converts the option string to a printf style string with the following args:
+// 1. timer, 2. event, 3. cpu0 eip, 4. device
+void 
+iofunctions::set_log_prefix(const char* prefix) {
+       
+       strcpy(logprefix,prefix);
+}
+
+//  iofunctions::out( class, level, prefix, fmt, ap)
+//  DO NOT nest out() from ::info() and the like.
+//    fmt and ap retained for direct printinf from iofunctions only!
+
+void
+iofunctions::out(int f, int l, const char *prefix, const char *fmt, va_list ap)
+{
+       char c=' ', *s;
+       assert (magic==MAGIC_LOGNUM);
+       assert (this != NULL);
+       assert (logfd != NULL);
+
+       //if( showtick )
+       //      fprintf(logfd, "%011lld", bx_pc_system.time_ticks());
+
+       switch(l) {
+               case LOGLEV_INFO: c='i'; break;
+               case LOGLEV_PANIC: c='p'; break;
+               case LOGLEV_PASS: c='s'; break;
+               case LOGLEV_ERROR: c='e'; break;
+               case LOGLEV_DEBUG: c='d'; break;
+               default: break;
+       }
+       //fprintf(logfd, "-%c",c);
+
+       //if(prefix != NULL)
+       //      fprintf(logfd, "%s ", prefix);
+
+       s=logprefix;
+       while(*s) {
+         switch(*s) {
+           case '%':
+             if(*(s+1))s++;
+             else break;
+             switch(*s) {
+               case 'd':
+                  fprintf(logfd, "%s", prefix==NULL?"":prefix);
+                 break;
+               case 't':
+                  fprintf(logfd, "%011lld", bx_pc_system.time_ticks());
+                 break;
+#ifndef BX_USE_VMX
+               case 'i':
+                  fprintf(logfd, "%08x", BX_CPU(0)==NULL?0:BX_CPU(0)->dword.eip);
+                 break;
+#endif
+               case 'e':
+                  fprintf(logfd, "%c", c);
+                 break;
+               case '%':
+                  fprintf(logfd,"%%");
+                 break;
+               default:
+                  fprintf(logfd,"%%%c",*s);
+               }
+              break;
+           default :
+              fprintf(logfd,"%c",*s);
+           }
+         s++;
+          }
+
+        fprintf(logfd," ");
+
+       if(l==LOGLEV_PANIC)
+               fprintf(logfd, ">>PANIC<< ");
+       if(l==LOGLEV_PASS)
+               fprintf(logfd, ">>PASS<< ");
+
+       vfprintf(logfd, fmt, ap);
+       fprintf(logfd, "\n");
+       fflush(logfd);
+
+       return;
+}
+
+iofunctions::iofunctions(FILE *fs)
+{
+       init();
+       init_log(fs);
+}
+
+iofunctions::iofunctions(const char *fn)
+{
+       init();
+       init_log(fn);
+}
+
+iofunctions::iofunctions(int fd)
+{
+       init();
+       init_log(fd);
+}
+
+iofunctions::iofunctions(void)
+{
+       this->init();
+}
+
+iofunctions::~iofunctions(void)
+{
+       // flush before erasing magic number, or flush does nothing.
+       this->flush();
+       this->magic=0;
+}
+
+#define LOG_THIS genlog->
+
+int logfunctions::default_onoff[N_LOGLEV] = {
+  ACT_IGNORE,  // ignore debug
+  ACT_REPORT,  // report info
+  ACT_REPORT,  // report error
+#if BX_WITH_WX
+  ACT_ASK,      // on panic, ask user what to do
+#else
+  ACT_FATAL,    // on panic, quit
+#endif
+  ACT_FATAL
+};
+
+logfunctions::logfunctions(void)
+{
+       prefix = NULL;
+       put(" ");
+       settype(GENLOG);
+       if (io == NULL && Allocio == 0) {
+               Allocio = 1;
+               io = new iofunc_t(stderr);
+       }
+       setio(io);
+       // BUG: unfortunately this can be called before the bochsrc is read,
+       // which means that the bochsrc has no effect on the actions.
+       for (int i=0; i<N_LOGLEV; i++)
+         onoff[i] = get_default_action(i);
+}
+
+logfunctions::logfunctions(iofunc_t *iofunc)
+{
+       prefix = NULL;
+       put(" ");
+       settype(GENLOG);
+       setio(iofunc);
+       // BUG: unfortunately this can be called before the bochsrc is read,
+       // which means that the bochsrc has no effect on the actions.
+       for (int i=0; i<N_LOGLEV; i++)
+         onoff[i] = get_default_action(i);
+}
+
+logfunctions::~logfunctions(void)
+{
+    if ( this->prefix )
+    {
+        free(this->prefix);
+        this->prefix = NULL;
+    }
+}
+
+void
+logfunctions::setio(iofunc_t *i)
+{
+       // add pointer to iofunction object to use
+       this->logio = i;
+       // give iofunction a pointer to me
+       i->add_logfn (this);
+}
+
+void
+logfunctions::put(char *p)
+{
+       char *tmpbuf;
+       tmpbuf=strdup("[     ]");// if we ever have more than 32 chars,
+                                                  //  we need to rethink this
+
+       if ( tmpbuf == NULL)
+       {
+           return ;                        /* allocation not successful */
+       }
+       if ( this->prefix != NULL )
+       {
+           free(this->prefix);             /* free previously allocated memory */
+           this->prefix = NULL;
+       }
+       int len=strlen(p);
+       for(int i=1;i<len+1;i++) {
+               tmpbuf[i]=p[i-1];
+       }
+               
+       switch(len) {
+       case  1: tmpbuf[2]=' ';
+       case  2: tmpbuf[3]=' ';
+       case  3: tmpbuf[4]=' ';
+       case  4: tmpbuf[5]=' ';
+       default: tmpbuf[6]=']'; tmpbuf[7]='\0'; break;
+       }
+       
+       this->prefix=tmpbuf;
+}
+
+void
+logfunctions::settype(int t)
+{
+       type=t;
+}
+
+void
+logfunctions::info(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert (this != NULL);
+       assert (this->logio != NULL);
+
+       if(!onoff[LOGLEV_INFO]) return;
+
+       va_start(ap, fmt);
+       this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap);
+       if (onoff[LOGLEV_INFO] == ACT_ASK) 
+         ask (LOGLEV_INFO, this->prefix, fmt, ap);
+       if (onoff[LOGLEV_INFO] == ACT_FATAL) 
+         fatal (this->prefix, fmt, ap, 1);
+       va_end(ap);
+
+}
+
+void
+logfunctions::error(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert (this != NULL);
+       assert (this->logio != NULL);
+
+       if(!onoff[LOGLEV_ERROR]) return;
+
+       va_start(ap, fmt);
+       this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap);
+       if (onoff[LOGLEV_ERROR] == ACT_ASK) 
+         ask (LOGLEV_ERROR, this->prefix, fmt, ap);
+       if (onoff[LOGLEV_ERROR] == ACT_FATAL) 
+         fatal (this->prefix, fmt, ap, 1);
+       va_end(ap);
+}
+
+void
+logfunctions::panic(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert (this != NULL);
+       assert (this->logio != NULL);
+
+       // Special case for panics since they are so important.  Always print
+       // the panic to the log, no matter what the log action says.
+       //if(!onoff[LOGLEV_PANIC]) return;
+
+       va_start(ap, fmt);
+       this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap);
+
+       // This fixes a funny bug on linuxppc where va_list is no pointer but a struct
+       va_end(ap);
+       va_start(ap, fmt);
+
+       if (onoff[LOGLEV_PANIC] == ACT_ASK) 
+         ask (LOGLEV_PANIC, this->prefix, fmt, ap);
+       if (onoff[LOGLEV_PANIC] == ACT_FATAL) 
+         fatal (this->prefix, fmt, ap, 1);
+       va_end(ap);
+}
+
+void
+logfunctions::pass(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert (this != NULL);
+       assert (this->logio != NULL);
+
+       // Special case for panics since they are so important.  Always print
+       // the panic to the log, no matter what the log action says.
+       //if(!onoff[LOGLEV_PASS]) return;
+
+       va_start(ap, fmt);
+       this->logio->out(this->type,LOGLEV_PASS,this->prefix, fmt, ap);
+
+       // This fixes a funny bug on linuxppc where va_list is no pointer but a struct
+       va_end(ap);
+       va_start(ap, fmt);
+
+       if (onoff[LOGLEV_PASS] == ACT_ASK) 
+         ask (LOGLEV_PASS, this->prefix, fmt, ap);
+       if (onoff[LOGLEV_PASS] == ACT_FATAL) 
+         fatal (this->prefix, fmt, ap, 101);
+       va_end(ap);
+}
+
+void
+logfunctions::ldebug(const char *fmt, ...)
+{
+       va_list ap;
+
+       assert (this != NULL);
+       assert (this->logio != NULL);
+
+       if(!onoff[LOGLEV_DEBUG]) return;
+
+       va_start(ap, fmt);
+       this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap);
+       if (onoff[LOGLEV_DEBUG] == ACT_ASK) 
+         ask (LOGLEV_DEBUG, this->prefix, fmt, ap);
+       if (onoff[LOGLEV_DEBUG] == ACT_FATAL) 
+         fatal (this->prefix, fmt, ap, 1);
+       va_end(ap);
+}
+
+void
+logfunctions::ask (int level, const char *prefix, const char *fmt, va_list ap)
+{
+  // Guard against reentry on ask() function.  The danger is that some
+  // function that's called within ask() could trigger another
+  // BX_PANIC that could call ask() again, leading to infinite
+  // recursion and infinite asks.
+  static char in_ask_already = 0;
+  char buf1[1024];
+  if (in_ask_already) {
+    fprintf (stderr, "logfunctions::ask() should not reenter!!\n");
+    return;
+  }
+  in_ask_already = 1;
+  vsprintf (buf1, fmt, ap);
+  // FIXME: facility set to 0 because it's unknown.
+
+  // update vga screen.  This is useful because sometimes useful messages
+  // are printed on the screen just before a panic.  It's also potentially
+  // dangerous if this function calls ask again...  That's why I added
+  // the reentry check above.
+  if (SIM->get_init_done()) DEV_vga_refresh();
+
+#if !BX_EXTERNAL_DEBUGGER
+  // ensure the text screen is showing
+  SIM->set_display_mode (DISP_MODE_CONFIG);
+  int val = SIM->log_msg (prefix, level, buf1);
+  switch (val)
+  {
+    case BX_LOG_ASK_CHOICE_CONTINUE:
+      break;
+    case BX_LOG_ASK_CHOICE_CONTINUE_ALWAYS:
+      // user said continue, and don't "ask" for this facility again.
+      setonoff (level, ACT_REPORT);
+      break;
+    case BX_LOG_ASK_CHOICE_DIE:
+      bx_user_quit = 1;
+      in_ask_already = 0;  // because fatal will longjmp out
+      fatal (prefix, fmt, ap, 1);
+      // should never get here
+      BX_PANIC (("in ask(), fatal() should never return!"));
+      break;
+    case BX_LOG_ASK_CHOICE_DUMP_CORE:
+      fprintf (stderr, "User chose to dump core...\n");
+#if BX_HAVE_ABORT
+      abort ();
+#else
+      // do something highly illegal that should kill the process.
+      // Hey, this is fun!
+      {
+      char *crashptr = (char *)0; char c = *crashptr;
+      }
+      fprintf (stderr, "Sorry, I couldn't find your abort() function.  Exiting.");
+      exit (0);
+#endif
+#if BX_DEBUGGER
+    case BX_LOG_ASK_CHOICE_ENTER_DEBUG:
+      // user chose debugger.  To "drop into the debugger" we just set the
+      // interrupt_requested bit and continue execution.  Before the next
+      // instruction, it should notice the user interrupt and return to
+      // the debugger.
+      bx_guard.interrupt_requested = 1;
+      break;
+#endif
+    default:
+      // this happens if panics happen before the callback is initialized
+      // in gui/control.cc.
+      fprintf (stderr, "WARNING: log_msg returned unexpected value %d\n", val);
+  }
+#else
+  // external debugger ask code goes here
+#endif
+  // return to simulation mode
+  SIM->set_display_mode (DISP_MODE_SIM);
+  in_ask_already = 0;
+}
+
+#if BX_WITH_CARBON
+/* Panic button to display fatal errors.
+  Completely self contained, can't rely on carbon.cc being available */
+static void carbonFatalDialog(const char *error, const char *exposition)
+{
+  DialogRef                     alertDialog;
+  CFStringRef                   cfError;
+  CFStringRef                   cfExposition;
+  DialogItemIndex               index;
+  AlertStdCFStringAlertParamRec alertParam = {0};
+  
+  // Init libraries
+  InitCursor();
+  // Assemble dialog
+  cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII);
+  if(exposition != NULL)
+  {
+    cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII);
+  }
+  else { cfExposition = NULL; }
+  alertParam.version       = kStdCFStringAlertVersionOne;
+  alertParam.defaultText   = CFSTR("Quit");
+  alertParam.position      = kWindowDefaultPosition;
+  alertParam.defaultButton = kAlertStdAlertOKButton;
+  // Display Dialog
+  CreateStandardAlert(
+    kAlertStopAlert,
+    cfError,
+    cfExposition,       /* can be NULL */
+    &alertParam,             /* can be NULL */
+    &alertDialog);
+  RunStandardAlert( alertDialog, NULL, &index);
+  // Cleanup
+  CFRelease( cfError );
+  if( cfExposition != NULL ) { CFRelease( cfExposition ); }
+}
+#endif
+
+void
+logfunctions::fatal (const char *prefix, const char *fmt, va_list ap, int exit_status)
+{
+  bx_atexit();
+#if BX_WITH_CARBON
+  if(!isatty(STDIN_FILENO) && !SIM->get_init_done())
+  {
+    char buf1[1024];
+    char buf2[1024];
+    vsprintf (buf1, fmt, ap);
+    sprintf (buf2, "Bochs startup error\n%s", buf1);
+    carbonFatalDialog(buf2,
+      "For more information, try running Bochs within Terminal by clicking on \"bochs.scpt\".");
+  }
+#endif
+#if !BX_WITH_WX
+  static char *divider = "========================================================================";
+  fprintf (stderr, "%s\n", divider);
+  fprintf (stderr, "Bochs is exiting with the following message:\n");
+  fprintf (stderr, "%s ", prefix);
+  vfprintf (stderr, fmt, ap);
+  fprintf (stderr, "\n%s\n", divider);
+#endif
+#if 0 && defined(WIN32)
+#error disabled because it is not working yet!
+  // wait for a keypress before quitting.  Depending on how bochs is
+  // installed, the console window can disappear before the user has
+  // a chance to read the final message.
+  fprintf (stderr, "\n\nPress Enter to exit...\n");
+  char buf[8];
+  fgets (buf, 8, stdin);
+#endif
+#if !BX_DEBUGGER
+  BX_EXIT(exit_status);
+#else
+  static bx_bool dbg_exit_called = 0;
+  if (dbg_exit_called == 0) {
+    dbg_exit_called = 1;
+    bx_dbg_exit(exit_status);
+    }
+#endif
+  // not safe to use BX_* log functions in here.
+  fprintf (stderr, "fatal() should never return, but it just did\n");
+}
+
+iofunc_t *io = NULL;
+logfunc_t *genlog = NULL;
+
+void bx_center_print (FILE *file, char *line, int maxwidth)
+{
+  int imax;
+  int len = strlen(line);
+  if (len > maxwidth)
+    BX_PANIC (("bx_center_print: line is too long: '%s'", line));
+  imax = (maxwidth - len) >> 1;
+  for (int i=0; i<imax; i++) fputc (' ', file);
+  fputs (line, file);
+}
+
+
diff --git a/tools/ioemu/iodev/main.cc b/tools/ioemu/iodev/main.cc
new file mode 100644 (file)
index 0000000..763b8b2
--- /dev/null
@@ -0,0 +1,4066 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: main.cc,v 1.256.2.3 2004/02/08 14:39:50 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//  Copyright (C) 2004  Arun Sharma <arun.sharma@intel.com>
+//  Copyright (C) 2004  Intel Corp
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#include "bochs.h"
+#include <assert.h>
+#include "state_file.h"
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+extern "C" {
+#include <signal.h>
+}
+
+#if BX_GUI_SIGHANDLER
+bx_bool bx_gui_sighandler = 0;
+#endif
+
+// single processor simulation, so there's one of everything
+BOCHSAPI BX_CPU_C    bx_cpu;
+BOCHSAPI BX_MEM_C    bx_mem;
+
+int xc_handle;
+int bochsrc_include_count = 0;
+
+// some prototypes from iodev/
+// I want to stay away from including iodev/iodev.h here
+Bit32u bx_unmapped_io_read_handler(Bit32u address, unsigned io_len);
+void   bx_unmapped_io_write_handler(Bit32u address, Bit32u value,
+                                    unsigned io_len);
+void   bx_close_harddrive(void);
+
+
+void bx_init_bx_dbg (void);
+static char *divider = "========================================================================";
+static logfunctions thePluginLog;
+logfunctions *pluginlog = &thePluginLog;
+
+bx_startup_flags_t bx_startup_flags;
+bx_bool bx_user_quit;
+
+/* typedefs */
+
+#define LOG_THIS genlog->
+
+#if ( BX_PROVIDE_DEVICE_MODELS==1 )
+bx_pc_system_c bx_pc_system;
+class state_file state_stuff("state_file.out", "options");
+#endif
+
+bx_debug_t bx_dbg;
+
+bx_options_t bx_options; // initialized in bx_init_options()
+char *bochsrc_filename = NULL;
+
+static Bit32s parse_line_unformatted(char *context, char *line);
+static Bit32s parse_line_formatted(char *context, int num_params, char *params[]);
+static int parse_bochsrc(char *rcfile);
+
+static Bit64s
+bx_param_handler (bx_param_c *param, int set, Bit64s val)
+{
+  bx_id id = param->get_id ();
+  switch (id) {
+    case BXP_VGA_UPDATE_INTERVAL:
+      // if after init, notify the vga device to change its timer.
+      if (set && SIM->get_init_done ())
+        DEV_vga_set_update_interval (val);
+      break;
+    case BXP_MOUSE_ENABLED:
+      // if after init, notify the GUI
+      if (set && SIM->get_init_done ()) {
+        bx_gui->mouse_enabled_changed (val!=0);
+        DEV_mouse_enabled_changed (val!=0);
+      }
+      break;
+    case BXP_NE2K_PRESENT:
+      if (set) {
+        int enable = (val != 0);
+        SIM->get_param (BXP_NE2K_IOADDR)->set_enabled (enable);
+        SIM->get_param (BXP_NE2K_IRQ)->set_enabled (enable);
+        SIM->get_param (BXP_NE2K_MACADDR)->set_enabled (enable);
+        SIM->get_param (BXP_NE2K_ETHMOD)->set_enabled (enable);
+        SIM->get_param (BXP_NE2K_ETHDEV)->set_enabled (enable);
+        SIM->get_param (BXP_NE2K_SCRIPT)->set_enabled (enable);
+      }
+      break;
+    case BXP_LOAD32BITOS_WHICH:
+      if (set) {
+        int enable = (val != Load32bitOSNone);
+        SIM->get_param (BXP_LOAD32BITOS_PATH)->set_enabled (enable);
+        SIM->get_param (BXP_LOAD32BITOS_IOLOG)->set_enabled (enable);
+        SIM->get_param (BXP_LOAD32BITOS_INITRD)->set_enabled (enable);
+      }
+      break;
+    case BXP_ATA0_MASTER_STATUS:
+    case BXP_ATA0_SLAVE_STATUS:
+    case BXP_ATA1_MASTER_STATUS:
+    case BXP_ATA1_SLAVE_STATUS:
+    case BXP_ATA2_MASTER_STATUS:
+    case BXP_ATA2_SLAVE_STATUS:
+    case BXP_ATA3_MASTER_STATUS:
+    case BXP_ATA3_SLAVE_STATUS:
+      if ((set) && (SIM->get_init_done ())) {
+        Bit8u device = id - BXP_ATA0_MASTER_STATUS;
+        Bit32u handle = DEV_hd_get_device_handle (device/2, device%2);
+        DEV_hd_set_cd_media_status(handle, val == BX_INSERTED);
+        bx_gui->update_drive_status_buttons ();
+      }
+      break;
+    case BXP_FLOPPYA_TYPE:
+      if ((set) && (!SIM->get_init_done ())) {
+        bx_options.floppya.Odevtype->set (val);
+      }
+      break;
+    case BXP_FLOPPYA_STATUS:
+      if ((set) && (SIM->get_init_done ())) {
+        DEV_floppy_set_media_status(0, val == BX_INSERTED);
+        bx_gui->update_drive_status_buttons ();
+      }
+      break;
+    case BXP_FLOPPYB_TYPE:
+      if ((set) && (!SIM->get_init_done ())) {
+        bx_options.floppyb.Odevtype->set (val);
+      }
+      break;
+    case BXP_FLOPPYB_STATUS:
+      if ((set) && (SIM->get_init_done ())) {
+        DEV_floppy_set_media_status(1, val == BX_INSERTED);
+        bx_gui->update_drive_status_buttons ();
+      }
+      break;
+    case BXP_KBD_PASTE_DELAY:
+      if ((set) && (SIM->get_init_done ())) {
+        DEV_kbd_paste_delay_changed ();
+        }
+      break;
+
+    case BXP_ATA0_MASTER_MODE:
+    case BXP_ATA0_SLAVE_MODE:
+    case BXP_ATA1_MASTER_MODE:
+    case BXP_ATA1_SLAVE_MODE:
+    case BXP_ATA2_MASTER_MODE:
+    case BXP_ATA2_SLAVE_MODE:
+    case BXP_ATA3_MASTER_MODE:
+    case BXP_ATA3_SLAVE_MODE:
+      if (set) {
+        int device = id - BXP_ATA0_MASTER_MODE;
+        switch (val) {
+          case BX_ATA_MODE_UNDOABLE:
+          case BX_ATA_MODE_VOLATILE:
+          //case BX_ATA_MODE_Z_UNDOABLE:
+          //case BX_ATA_MODE_Z_VOLATILE:
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (1);
+            break;
+          default:
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (0);
+          }
+        }
+      break;
+
+    case BXP_ATA0_MASTER_TYPE:
+    case BXP_ATA0_SLAVE_TYPE:
+    case BXP_ATA1_MASTER_TYPE:
+    case BXP_ATA1_SLAVE_TYPE:
+    case BXP_ATA2_MASTER_TYPE:
+    case BXP_ATA2_SLAVE_TYPE:
+    case BXP_ATA3_MASTER_TYPE:
+    case BXP_ATA3_SLAVE_TYPE:
+      if (set) {
+        int device = id - BXP_ATA0_MASTER_TYPE;
+        switch (val) {
+          case BX_ATA_DEVICE_DISK:
+            SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODE + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1);
+            //SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_runtime_param (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_runtime_param (0);
+            break;
+          case BX_ATA_DEVICE_CDROM:
+            SIM->get_param_num ((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->set (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODE + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_JOURNAL + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_CYLINDERS + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_HEADS + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_SPT + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_MODEL + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_BIOSDETECT + device))->set_enabled (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_TRANSLATION + device))->set_enabled (0);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_PATH + device))->set_runtime_param (1);
+            SIM->get_param ((bx_id)(BXP_ATA0_MASTER_STATUS + device))->set_runtime_param (1);
+            break;
+          }
+        }
+      break;
+    default:
+      BX_PANIC (("bx_param_handler called with unknown id %d", id));
+      return -1;
+  }
+  return val;
+}
+
+char *bx_param_string_handler (bx_param_string_c *param, int set, char *val, int maxlen)
+{
+  bx_id id = param->get_id ();
+
+  int empty = 0;
+  if ((strlen(val) < 1) || !strcmp ("none", val)) {
+    empty = 1;
+    val = "none";
+  }
+  switch (id) {
+    case BXP_FLOPPYA_PATH:
+      if (set==1) {
+        if (SIM->get_init_done ()) {
+          if (empty) {
+            DEV_floppy_set_media_status(0, 0);
+            bx_gui->update_drive_status_buttons ();
+          } else {
+            if (!SIM->get_param_num(BXP_FLOPPYA_TYPE)->get_enabled()) {
+              BX_ERROR(("Cannot add a floppy drive at runtime"));
+              bx_options.floppya.Opath->set ("none");
+            }
+          }
+          if ((DEV_floppy_present()) &&
+              (SIM->get_param_num(BXP_FLOPPYA_STATUS)->get () == BX_INSERTED)) {
+            // tell the device model that we removed, then inserted the disk
+            DEV_floppy_set_media_status(0, 0);
+            DEV_floppy_set_media_status(0, 1);
+          }
+        } else {
+          SIM->get_param_num(BXP_FLOPPYA_DEVTYPE)->set_enabled (!empty);
+          SIM->get_param_num(BXP_FLOPPYA_TYPE)->set_enabled (!empty);
+          SIM->get_param_num(BXP_FLOPPYA_STATUS)->set_enabled (!empty);
+        }
+      }
+      break;
+    case BXP_FLOPPYB_PATH:
+      if (set==1) {
+        if (SIM->get_init_done ()) {
+          if (empty) {
+            DEV_floppy_set_media_status(1, 0);
+            bx_gui->update_drive_status_buttons ();
+          } else {
+            if (!SIM->get_param_num(BXP_FLOPPYB_TYPE)->get_enabled ()) {
+              BX_ERROR(("Cannot add a floppy drive at runtime"));
+              bx_options.floppyb.Opath->set ("none");
+            }
+          }
+          if ((DEV_floppy_present()) &&
+              (SIM->get_param_num(BXP_FLOPPYB_STATUS)->get () == BX_INSERTED)) {
+            // tell the device model that we removed, then inserted the disk
+            DEV_floppy_set_media_status(1, 0);
+            DEV_floppy_set_media_status(1, 1);
+          }
+        } else {
+          SIM->get_param_num(BXP_FLOPPYB_DEVTYPE)->set_enabled (!empty);
+          SIM->get_param_num(BXP_FLOPPYB_TYPE)->set_enabled (!empty);
+          SIM->get_param_num(BXP_FLOPPYB_STATUS)->set_enabled (!empty);
+        }
+      }
+      break;
+
+    case BXP_ATA0_MASTER_PATH:
+    case BXP_ATA0_SLAVE_PATH:
+    case BXP_ATA1_MASTER_PATH:
+    case BXP_ATA1_SLAVE_PATH:
+    case BXP_ATA2_MASTER_PATH:
+    case BXP_ATA2_SLAVE_PATH:
+    case BXP_ATA3_MASTER_PATH:
+    case BXP_ATA3_SLAVE_PATH:
+      if (set==1) {
+        if (SIM->get_init_done ()) {
+
+          Bit8u device = id - BXP_ATA0_MASTER_PATH;
+          Bit32u handle = DEV_hd_get_device_handle(device/2, device%2);
+
+          if (empty) {
+            DEV_hd_set_cd_media_status(handle, 0);
+            bx_gui->update_drive_status_buttons ();
+          } else {
+            if (!SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_PRESENT + device))->get ()) {
+              BX_ERROR(("Cannot add a cdrom drive at runtime"));
+              bx_options.atadevice[device/2][device%2].Opresent->set (0);
+            }
+            if (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () != BX_ATA_DEVICE_CDROM) {
+              BX_ERROR(("Device is not a cdrom drive"));
+              bx_options.atadevice[device/2][device%2].Opresent->set (0);
+            }
+          }
+          if (DEV_hd_present() &&
+              (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_STATUS + device))->get () == BX_INSERTED) &&
+              (SIM->get_param_num((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get () == BX_ATA_DEVICE_CDROM)) {
+            // tell the device model that we removed, then inserted the cd
+            DEV_hd_set_cd_media_status(handle, 0);
+            DEV_hd_set_cd_media_status(handle, 1);
+          }
+        }
+      }
+      break;
+    
+    case BXP_SCREENMODE:
+      if (set==1) {
+        BX_INFO (("Screen mode changed to %s", val));
+      }
+      break;
+    default:
+        BX_PANIC (("bx_string_handler called with unexpected parameter %d", param->get_id()));
+  }
+  return val;
+}
+
+static int
+bx_param_enable_handler (bx_param_c *param, int val)
+{
+  bx_id id = param->get_id ();
+  switch (id) {
+    case BXP_ATA0_MASTER_STATUS:
+    case BXP_ATA0_SLAVE_STATUS:
+    case BXP_ATA1_MASTER_STATUS:
+    case BXP_ATA1_SLAVE_STATUS:
+    case BXP_ATA2_MASTER_STATUS:
+    case BXP_ATA2_SLAVE_STATUS:
+    case BXP_ATA3_MASTER_STATUS:
+    case BXP_ATA3_SLAVE_STATUS:
+      if (val != 0) {
+        Bit8u device = id - BXP_ATA0_MASTER_STATUS;
+  
+        switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get()) {
+          case BX_ATA_DEVICE_CDROM:
+            return (1);
+            break;
+          }
+        }
+      return (0);
+      break;
+
+    case BXP_ATA0_MASTER_JOURNAL:
+    case BXP_ATA0_SLAVE_JOURNAL:
+    case BXP_ATA1_MASTER_JOURNAL:
+    case BXP_ATA1_SLAVE_JOURNAL:
+    case BXP_ATA2_MASTER_JOURNAL:
+    case BXP_ATA2_SLAVE_JOURNAL:
+    case BXP_ATA3_MASTER_JOURNAL:
+    case BXP_ATA3_SLAVE_JOURNAL:
+      if (val != 0) {
+        Bit8u device = id - BXP_ATA0_MASTER_JOURNAL;
+  
+        switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_TYPE + device))->get()) {
+          case BX_ATA_DEVICE_DISK:
+            switch (SIM->get_param_enum ((bx_id)(BXP_ATA0_MASTER_MODE + device))->get()) {
+              case BX_ATA_MODE_UNDOABLE:
+              case BX_ATA_MODE_VOLATILE:
+              //case BX_ATA_MODE_Z_UNDOABLE:
+              //case BX_ATA_MODE_Z_VOLATILE:
+              return (1);
+              break;
+            }
+          }
+        }
+      return (0);
+      break;
+
+    default:
+      BX_PANIC (("bx_param_handler called with unknown id %d", id));
+  }
+  return val;
+}
+
+
+
+void bx_init_options ()
+{
+  int i;
+  bx_list_c *menu;
+  bx_list_c *deplist;
+  char name[1024], descr[1024], label[1024];
+
+  memset (&bx_options, 0, sizeof(bx_options));
+
+  // quick start option, set by command line arg
+  new bx_param_enum_c (BXP_BOCHS_START,
+      "Bochs start types",
+      "Bochs start types",
+      bochs_start_names,
+      BX_RUN_START,
+      BX_QUICK_START);
+
+  // floppya
+  bx_options.floppya.Opath = new bx_param_filename_c (BXP_FLOPPYA_PATH,
+      "floppya:path",
+      "Pathname of first floppy image file or device.  If you're booting from floppy, this should be a bootable floppy.",
+      "", BX_PATHNAME_LEN);
+  bx_options.floppya.Opath->set_ask_format ("Enter new filename, or 'none' for no disk: [%s] ");
+  bx_options.floppya.Opath->set_label ("First floppy image/device");
+  bx_options.floppya.Odevtype = new bx_param_enum_c (BXP_FLOPPYA_DEVTYPE,
+      "floppya:devtype",
+      "Type of floppy drive",
+      floppy_type_names,
+      BX_FLOPPY_NONE,
+      BX_FLOPPY_NONE);
+  bx_options.floppya.Otype = new bx_param_enum_c (BXP_FLOPPYA_TYPE,
+      "floppya:type",
+      "Type of floppy disk",
+      floppy_type_names,
+      BX_FLOPPY_NONE,
+      BX_FLOPPY_NONE);
+  bx_options.floppya.Otype->set_ask_format ("What type of floppy disk? [%s] ");
+  bx_options.floppya.Ostatus = new bx_param_enum_c (BXP_FLOPPYA_STATUS,
+      "Is floppya inserted",
+      "Inserted or ejected",
+      floppy_status_names,
+      BX_INSERTED,
+      BX_EJECTED);
+  bx_options.floppya.Ostatus->set_ask_format ("Is the floppy inserted or ejected? [%s] ");
+  bx_options.floppya.Opath->set_format ("%s");
+  bx_options.floppya.Otype->set_format ("size=%s");
+  bx_options.floppya.Ostatus->set_format ("%s");
+  bx_param_c *floppya_init_list[] = {
+    // if the order "path,type,status" changes, corresponding changes must
+    // be made in gui/wxmain.cc, MyFrame::editFloppyConfig.
+    bx_options.floppya.Opath,
+    bx_options.floppya.Otype,
+    bx_options.floppya.Ostatus,
+    NULL
+  };
+  menu = new bx_list_c (BXP_FLOPPYA, "Floppy Disk 0", "All options for first floppy disk", floppya_init_list);
+  menu->get_options ()->set (menu->SERIES_ASK);
+  bx_options.floppya.Opath->set_handler (bx_param_string_handler);
+  bx_options.floppya.Opath->set ("none");
+  bx_options.floppya.Otype->set_handler (bx_param_handler);
+  bx_options.floppya.Ostatus->set_handler (bx_param_handler);
+
+  bx_options.floppyb.Opath = new bx_param_filename_c (BXP_FLOPPYB_PATH,
+      "floppyb:path",
+      "Pathname of second floppy image file or device.",
+      "", BX_PATHNAME_LEN);
+  bx_options.floppyb.Opath->set_ask_format ("Enter new filename, or 'none' for no disk: [%s] ");
+  bx_options.floppyb.Opath->set_label ("Second floppy image/device");
+  bx_options.floppyb.Odevtype = new bx_param_enum_c (BXP_FLOPPYB_DEVTYPE,
+      "floppyb:devtype",
+      "Type of floppy drive",
+      floppy_type_names,
+      BX_FLOPPY_NONE,
+      BX_FLOPPY_NONE);
+  bx_options.floppyb.Otype = new bx_param_enum_c (BXP_FLOPPYB_TYPE,
+      "floppyb:type",
+      "Type of floppy disk",
+      floppy_type_names,
+      BX_FLOPPY_NONE,
+      BX_FLOPPY_NONE);
+  bx_options.floppyb.Otype->set_ask_format ("What type of floppy disk? [%s] ");
+  bx_options.floppyb.Ostatus = new bx_param_enum_c (BXP_FLOPPYB_STATUS,
+      "Is floppyb inserted",
+      "Inserted or ejected",
+      floppy_status_names,
+      BX_INSERTED,
+      BX_EJECTED);
+  bx_options.floppyb.Ostatus->set_ask_format ("Is the floppy inserted or ejected? [%s] ");
+  bx_options.floppyb.Opath->set_format ("%s");
+  bx_options.floppyb.Otype->set_format ("size=%s");
+  bx_options.floppyb.Ostatus->set_format ("%s");
+  bx_param_c *floppyb_init_list[] = {
+    bx_options.floppyb.Opath,
+    bx_options.floppyb.Otype,
+    bx_options.floppyb.Ostatus,
+    NULL
+  };
+  menu = new bx_list_c (BXP_FLOPPYB, "Floppy Disk 1", "All options for second floppy disk", floppyb_init_list);
+  menu->get_options ()->set (menu->SERIES_ASK);
+  bx_options.floppyb.Opath->set_handler (bx_param_string_handler);
+  bx_options.floppyb.Opath->set ("none");
+  bx_options.floppyb.Otype->set_handler (bx_param_handler);
+  bx_options.floppyb.Ostatus->set_handler (bx_param_handler);
+
+  // disk options
+
+  // FIXME use descr and name
+  char *s_atachannel[] = {
+    "ATA channel 0",
+    "ATA channel 1",
+    "ATA channel 2",
+    "ATA channel 3",
+    };
+  char *s_atadevice[4][2] = {
+    { "First HD/CD on channel 0",
+      "Second HD/CD on channel 0" },
+    { "First HD/CD on channel 1",
+    "Second HD/CD on channel 1" },
+    { "First HD/CD on channel 2",
+    "Second HD/CD on channel 2" },
+    { "First HD/CD on channel 3",
+    "Second HD/CD on channel 3" }
+    };
+  Bit16u ata_default_ioaddr1[BX_MAX_ATA_CHANNEL] = {
+    0x1f0, 0x170, 0x1e8, 0x168 
+  };
+  Bit16u ata_default_ioaddr2[BX_MAX_ATA_CHANNEL] = {
+    0x3f0, 0x370, 0x3e0, 0x360 
+  };
+  Bit8u ata_default_irq[BX_MAX_ATA_CHANNEL] = { 
+    14, 15, 11, 9 
+  };
+
+  bx_list_c *ata[BX_MAX_ATA_CHANNEL];
+  bx_list_c *ata_menu[BX_MAX_ATA_CHANNEL];
+
+  Bit8u channel;
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel ++) {
+
+    ata[channel] = new bx_list_c ((bx_id)(BXP_ATAx(channel)), s_atachannel[channel], s_atachannel[channel], 8);
+    ata[channel]->get_options ()->set (bx_list_c::SERIES_ASK);
+
+    ata[channel]->add (bx_options.ata[channel].Opresent = new bx_param_bool_c ((bx_id)(BXP_ATAx_PRESENT(channel)),
+      "ata:present",                                
+      "Controls whether ata channel is installed or not",
+      0));
+
+    ata[channel]->add (bx_options.ata[channel].Oioaddr1 = new bx_param_num_c ((bx_id)(BXP_ATAx_IOADDR1(channel)),
+      "ata:ioaddr1",
+      "IO adress of ata command block",
+      0, 0xffff,
+      ata_default_ioaddr1[channel]));
+
+    ata[channel]->add (bx_options.ata[channel].Oioaddr2 = new bx_param_num_c ((bx_id)(BXP_ATAx_IOADDR2(channel)),
+      "ata:ioaddr2",
+      "IO adress of ata control block",
+      0, 0xffff,
+      ata_default_ioaddr2[channel]));
+
+    ata[channel]->add (bx_options.ata[channel].Oirq = new bx_param_num_c ((bx_id)(BXP_ATAx_IRQ(channel)),
+      "ata:irq",
+      "IRQ used by this ata channel",
+      0, 15,
+      ata_default_irq[channel]));
+
+    // all items in the ata[channel] menu depend on the present flag.
+    // The menu list is complete, but a few dependent_list items will
+    // be added later.  Use clone() to make a copy of the dependent_list
+    // so that it can be changed without affecting the menu.
+    bx_options.ata[channel].Opresent->set_dependent_list (
+        ata[channel]->clone());
+
+    for (Bit8u slave=0; slave<2; slave++) {
+
+      menu = bx_options.atadevice[channel][slave].Omenu = new bx_list_c ((bx_id)(BXP_ATAx_DEVICE(channel,slave)),
+          s_atadevice[channel][slave], 
+          s_atadevice[channel][slave],
+          BXP_PARAMS_PER_ATA_DEVICE + 1 );
+      menu->get_options ()->set (menu->SERIES_ASK);
+
+      menu->add (bx_options.atadevice[channel][slave].Opresent = new bx_param_bool_c ((bx_id)(BXP_ATAx_DEVICE_PRESENT(channel,slave)),
+        "ata-device:present",                                
+        "Controls whether ata device is installed or not",  
+        0));
+
+      menu->add (bx_options.atadevice[channel][slave].Otype = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_TYPE(channel,slave)),
+          "ata-device:type",
+          "Type of ATA device (disk or cdrom)",
+          atadevice_type_names,
+          BX_ATA_DEVICE_DISK,
+          BX_ATA_DEVICE_DISK));
+
+      menu->add (bx_options.atadevice[channel][slave].Opath = new bx_param_filename_c ((bx_id)(BXP_ATAx_DEVICE_PATH(channel,slave)),
+          "ata-device:path",
+          "Pathname of the image or physical device (cdrom only)",
+          "", BX_PATHNAME_LEN));
+
+      menu->add (bx_options.atadevice[channel][slave].Omode = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_MODE(channel,slave)),
+          "ata-device:mode",
+          "Mode of the ATA harddisk",
+          atadevice_mode_names,
+          BX_ATA_MODE_FLAT,
+          BX_ATA_MODE_FLAT));
+
+      menu->add (bx_options.atadevice[channel][slave].Ostatus = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_STATUS(channel,slave)),
+       "ata-device:status",
+       "CD-ROM media status (inserted / ejected)",
+       atadevice_status_names,
+       BX_INSERTED,
+       BX_EJECTED));
+
+      menu->add (bx_options.atadevice[channel][slave].Ojournal = new bx_param_filename_c ((bx_id)(BXP_ATAx_DEVICE_JOURNAL(channel,slave)),
+          "ata-device:journal",
+          "Pathname of the journal file",
+          "", BX_PATHNAME_LEN));
+
+      menu->add (bx_options.atadevice[channel][slave].Ocylinders = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_CYLINDERS(channel,slave)),
+          "ata-device:cylinders",
+          "Number of cylinders",
+          0, 65535,
+          0));
+      menu->add (bx_options.atadevice[channel][slave].Oheads = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_HEADS(channel,slave)),
+          "ata-device:heads",
+          "Number of heads",
+          0, 65535,
+          0));
+      menu->add (bx_options.atadevice[channel][slave].Ospt = new bx_param_num_c ((bx_id)(BXP_ATAx_DEVICE_SPT(channel,slave)),
+          "ata-device:spt",
+          "Number of sectors per track",
+          0, 65535,
+          0));
+      
+      menu->add (bx_options.atadevice[channel][slave].Omodel = new bx_param_string_c ((bx_id)(BXP_ATAx_DEVICE_MODEL(channel,slave)),
+       "ata-device:model",
+       "String returned by the 'identify device' command",
+       "Generic 1234", 40));
+
+      menu->add (bx_options.atadevice[channel][slave].Obiosdetect = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_BIOSDETECT(channel,slave)),
+       "ata-device:biosdetect",
+       "Type of bios detection",
+       atadevice_biosdetect_names,
+       BX_ATA_BIOSDETECT_AUTO,
+       BX_ATA_BIOSDETECT_NONE));
+
+      menu->add (bx_options.atadevice[channel][slave].Otranslation = new bx_param_enum_c ((bx_id)(BXP_ATAx_DEVICE_TRANSLATION(channel,slave)),
+       "How the ata-disk translation is done by the bios",
+       "Type of translation",
+       atadevice_translation_names,
+       BX_ATA_TRANSLATION_AUTO,
+       BX_ATA_TRANSLATION_NONE));
+
+      bx_options.atadevice[channel][slave].Opresent->set_dependent_list (
+          menu->clone ());
+      // the menu and all items on it depend on the Opresent flag
+      bx_options.atadevice[channel][slave].Opresent->get_dependent_list()->add(menu);
+      // the present flag depends on the ATA channel's present flag
+      bx_options.ata[channel].Opresent->get_dependent_list()->add (
+          bx_options.atadevice[channel][slave].Opresent);
+      }
+
+      // set up top level menu for ATA[i] controller configuration.  This list
+      // controls what will appear on the ATA configure dialog.  It now
+      // requests the USE_TAB_WINDOW display, which is implemented in wx.
+      char buffer[32];
+      sprintf (buffer, "Configure ATA%d", channel);
+      ata_menu[channel] = new bx_list_c ((bx_id)(BXP_ATAx_MENU(channel)), strdup(buffer), "", 4);
+      ata_menu[channel]->add (ata[channel]);
+      ata_menu[channel]->add (bx_options.atadevice[channel][0].Omenu);
+      ata_menu[channel]->add (bx_options.atadevice[channel][1].Omenu);
+      ata_menu[channel]->get_options()->set (bx_list_c::USE_TAB_WINDOW);
+    }
+
+  // Enable first ata interface by default, disable the others.
+  bx_options.ata[0].Opresent->set_initial_val(1);
+
+  // now that the dependence relationships are established, call set() on
+  // the ata device present params to set all enables correctly.
+  for (i=0; i<BX_MAX_ATA_CHANNEL; i++)
+    bx_options.ata[i].Opresent->set (i==0);
+
+  for (channel=0; channel<BX_MAX_ATA_CHANNEL; channel ++) {
+
+    bx_options.ata[channel].Opresent->set_ask_format ("Channel is enabled: [%s] ");
+    bx_options.ata[channel].Oioaddr1->set_ask_format ("Enter new ioaddr1: [0x%x] ");
+    bx_options.ata[channel].Oioaddr2->set_ask_format ("Enter new ioaddr2: [0x%x] ");
+    bx_options.ata[channel].Oirq->set_ask_format ("Enter new IRQ: [%d] ");
+#if BX_WITH_WX
+    bx_options.ata[channel].Opresent->set_label ("Enable this channel?");
+    bx_options.ata[channel].Oioaddr1->set_label ("I/O Address 1:");
+    bx_options.ata[channel].Oioaddr2->set_label ("I/O Address 2:");
+    bx_options.ata[channel].Oirq->set_label ("IRQ:");
+    bx_options.ata[channel].Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#else
+    bx_options.ata[channel].Opresent->set_format ("enabled: %s");
+    bx_options.ata[channel].Oioaddr1->set_format ("ioaddr1: 0x%x");
+    bx_options.ata[channel].Oioaddr2->set_format ("ioaddr2: 0x%x");
+    bx_options.ata[channel].Oirq->set_format ("irq: %d");
+#endif
+    bx_options.ata[channel].Oioaddr1->set_base (16);
+    bx_options.ata[channel].Oioaddr2->set_base (16);
+
+    for (Bit8u slave=0; slave<2; slave++) {
+
+      bx_options.atadevice[channel][slave].Opresent->set_ask_format (
+          "Device is enabled: [%s] ");
+      bx_options.atadevice[channel][slave].Otype->set_ask_format (
+          "Enter type of ATA device, disk or cdrom: [%s] ");
+      bx_options.atadevice[channel][slave].Omode->set_ask_format (
+          "Enter mode of ATA device, (flat, concat, etc.): [%s] ");
+      bx_options.atadevice[channel][slave].Opath->set_ask_format (
+          "Enter new filename: [%s] ");
+      bx_options.atadevice[channel][slave].Ocylinders->set_ask_format (
+          "Enter number of cylinders: [%d] ");
+      bx_options.atadevice[channel][slave].Oheads->set_ask_format (
+          "Enter number of heads: [%d] ");
+      bx_options.atadevice[channel][slave].Ospt->set_ask_format (
+          "Enter number of sectors per track: [%d] ");
+      bx_options.atadevice[channel][slave].Ostatus->set_ask_format (
+          "Is the device inserted or ejected? [%s] ");
+      bx_options.atadevice[channel][slave].Omodel->set_ask_format (
+          "Enter new model name: [%s]");
+      bx_options.atadevice[channel][slave].Otranslation->set_ask_format (
+          "Enter translation type: [%s]");
+      bx_options.atadevice[channel][slave].Obiosdetect->set_ask_format (
+          "Enter bios detection type: [%s]");
+      bx_options.atadevice[channel][slave].Ojournal->set_ask_format (
+          "Enter path of journal file: [%s]");
+
+#if BX_WITH_WX
+      bx_options.atadevice[channel][slave].Opresent->set_label (
+          "Enable this device?");
+      bx_options.atadevice[channel][slave].Otype->set_label (
+          "Type of ATA device:");
+      bx_options.atadevice[channel][slave].Omode->set_label (
+          "Type of disk image:");
+      bx_options.atadevice[channel][slave].Opath->set_label (
+          "Path or physical device name:");
+      bx_options.atadevice[channel][slave].Ocylinders->set_label (
+          "Cylinders:");
+      bx_options.atadevice[channel][slave].Oheads->set_label (
+          "Heads:");
+      bx_options.atadevice[channel][slave].Ospt->set_label (
+          "Sectors per track:");
+      bx_options.atadevice[channel][slave].Ostatus->set_label (
+          "Inserted?");
+      bx_options.atadevice[channel][slave].Omodel->set_label (
+          "Model name:");
+      bx_options.atadevice[channel][slave].Otranslation->set_label (
+          "Translation type:");
+      bx_options.atadevice[channel][slave].Obiosdetect->set_label (
+          "BIOS Detection:");
+      bx_options.atadevice[channel][slave].Ojournal->set_label (
+          "Path of journal file:");
+#else
+      bx_options.atadevice[channel][slave].Opresent->set_format ("enabled: %s");
+      bx_options.atadevice[channel][slave].Otype->set_format ("type %s");
+      bx_options.atadevice[channel][slave].Omode->set_format ("mode %s");
+      bx_options.atadevice[channel][slave].Opath->set_format ("path '%s'");
+      bx_options.atadevice[channel][slave].Ocylinders->set_format ("%d cylinders");
+      bx_options.atadevice[channel][slave].Oheads->set_format ("%d heads");
+      bx_options.atadevice[channel][slave].Ospt->set_format ("%d sectors/track");
+      bx_options.atadevice[channel][slave].Ostatus->set_format ("%s");
+      bx_options.atadevice[channel][slave].Omodel->set_format ("model '%s'");
+      bx_options.atadevice[channel][slave].Otranslation->set_format ("translation '%s'");
+      bx_options.atadevice[channel][slave].Obiosdetect->set_format ("biosdetect '%s'");
+      bx_options.atadevice[channel][slave].Ojournal->set_format ("journal is '%s'");
+#endif
+
+      bx_options.atadevice[channel][slave].Otype->set_handler (bx_param_handler);
+      bx_options.atadevice[channel][slave].Omode->set_handler (bx_param_handler);
+      bx_options.atadevice[channel][slave].Ostatus->set_handler (bx_param_handler);
+      bx_options.atadevice[channel][slave].Opath->set_handler (bx_param_string_handler);
+
+      // Set the enable_hanlders
+      bx_options.atadevice[channel][slave].Ojournal->set_enable_handler (bx_param_enable_handler);
+      bx_options.atadevice[channel][slave].Ostatus->set_enable_handler (bx_param_enable_handler);
+
+      }
+    }
+
+  bx_options.OnewHardDriveSupport = new bx_param_bool_c (BXP_NEWHARDDRIVESUPPORT,
+      "New hard drive support",
+      "Enables new features found on newer hard drives.",
+      1);
+
+  bx_options.Obootdrive = new bx_param_enum_c (BXP_BOOTDRIVE,
+      "bootdrive",
+      "Boot A, C or CD",
+      floppy_bootdisk_names,
+      BX_BOOT_FLOPPYA,
+      BX_BOOT_FLOPPYA);
+  bx_options.Obootdrive->set_format ("Boot from: %s drive");
+  bx_options.Obootdrive->set_ask_format ("Boot from floppy drive, hard drive or cdrom ? [%s] ");
+
+  bx_options.OfloppySigCheck = new bx_param_bool_c (BXP_FLOPPYSIGCHECK,
+      "Skip Floppy Boot Signature Check",
+      "Skips check for the 0xaa55 signature on floppy boot device.",
+      0);
+
+  // disk menu
+  bx_param_c *disk_menu_init_list[] = {
+    SIM->get_param (BXP_FLOPPYA),
+    SIM->get_param (BXP_FLOPPYB),
+    SIM->get_param (BXP_ATA0),
+    SIM->get_param (BXP_ATA0_MASTER),
+    SIM->get_param (BXP_ATA0_SLAVE),
+#if BX_MAX_ATA_CHANNEL>1
+    SIM->get_param (BXP_ATA1),
+    SIM->get_param (BXP_ATA1_MASTER),
+    SIM->get_param (BXP_ATA1_SLAVE),
+#endif
+#if BX_MAX_ATA_CHANNEL>2
+    SIM->get_param (BXP_ATA2),
+    SIM->get_param (BXP_ATA2_MASTER),
+    SIM->get_param (BXP_ATA2_SLAVE),
+#endif
+#if BX_MAX_ATA_CHANNEL>3
+    SIM->get_param (BXP_ATA3),
+    SIM->get_param (BXP_ATA3_MASTER),
+    SIM->get_param (BXP_ATA3_SLAVE),
+#endif
+    SIM->get_param (BXP_NEWHARDDRIVESUPPORT),
+    SIM->get_param (BXP_BOOTDRIVE),
+    SIM->get_param (BXP_FLOPPYSIGCHECK),
+    NULL
+  };
+  menu = new bx_list_c (BXP_MENU_DISK, "Bochs Disk Options", "diskmenu", disk_menu_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+  // memory options menu
+  bx_options.memory.Osize = new bx_param_num_c (BXP_MEM_SIZE,
+      "megs",
+      "Amount of RAM in megabytes",
+      1, BX_MAX_BIT32U,
+      BX_DEFAULT_MEM_MEGS);
+  bx_options.memory.Osize->set_ask_format ("Enter memory size (MB): [%d] ");
+#if BX_WITH_WX
+  bx_options.memory.Osize->set_label ("Memory size (megabytes)");
+  bx_options.memory.Osize->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#else
+  bx_options.memory.Osize->set_format ("Memory size in megabytes: %d");
+#endif
+
+  // initialize serial and parallel port options
+#define PAR_SER_INIT_LIST_MAX \
+  ((BXP_PARAMS_PER_PARALLEL_PORT * BX_N_PARALLEL_PORTS) \
+  + (BXP_PARAMS_PER_SERIAL_PORT * BX_N_SERIAL_PORTS) \
+  + (BXP_PARAMS_PER_USB_HUB * BX_N_USB_HUBS))
+  bx_param_c *par_ser_init_list[1+PAR_SER_INIT_LIST_MAX];
+  bx_param_c **par_ser_ptr = &par_ser_init_list[0];
+
+  // parallel ports
+  for (i=0; i<BX_N_PARALLEL_PORTS; i++) {
+        sprintf (name, "Enable parallel port #%d", i+1);
+        sprintf (descr, "Controls whether parallel port #%d is installed or not", i+1);
+        bx_options.par[i].Oenabled = new bx_param_bool_c (
+                BXP_PARPORTx_ENABLED(i+1), 
+                strdup(name), 
+                strdup(descr), 
+                (i==0)? 1 : 0);  // only enable #1 by default
+        sprintf (name, "Parallel port #%d output file", i+1);
+        sprintf (descr, "Data written to parport#%d by the guest OS is written to this file", i+1);
+        bx_options.par[i].Ooutfile = new bx_param_filename_c (
+                BXP_PARPORTx_OUTFILE(i+1), 
+                strdup(name), 
+                strdup(descr),
+                "", BX_PATHNAME_LEN);
+        deplist = new bx_list_c (BXP_NULL, 1);
+        deplist->add (bx_options.par[i].Ooutfile);
+        bx_options.par[i].Oenabled->set_dependent_list (deplist);
+        // add to menu
+        *par_ser_ptr++ = bx_options.par[i].Oenabled;
+        *par_ser_ptr++ = bx_options.par[i].Ooutfile;
+  }
+
+  // serial ports
+  for (i=0; i<BX_N_SERIAL_PORTS; i++) {
+        // options for COM port
+        sprintf (name, "Enable serial port #%d (COM%d)", i+1, i+1);
+        sprintf (descr, "Controls whether COM%d is installed or not", i+1);
+        bx_options.com[i].Oenabled = new bx_param_bool_c (
+                BXP_COMx_ENABLED(i+1),
+                strdup(name), 
+                strdup(descr), 
+                (i==0)?1 : 0);  // only enable the first by default
+        sprintf (name, "Pathname of the serial device for COM%d", i+1);
+        sprintf (descr, "The path can be a real serial device or a pty (X/Unix only)");
+        bx_options.com[i].Odev = new bx_param_filename_c (
+                BXP_COMx_PATH(i+1),
+                strdup(name), 
+                strdup(descr), 
+                "", BX_PATHNAME_LEN);
+        deplist = new bx_list_c (BXP_NULL, 1);
+        deplist->add (bx_options.com[i].Odev);
+        bx_options.com[i].Oenabled->set_dependent_list (deplist);
+        // add to menu
+        *par_ser_ptr++ = bx_options.com[i].Oenabled;
+        *par_ser_ptr++ = bx_options.com[i].Odev;
+  }
+
+  // usb hubs
+  for (i=0; i<BX_N_USB_HUBS; i++) {
+        // options for USB hub
+        sprintf (name, "usb%d:enabled", i+1);
+        sprintf (descr, "Controls whether USB%d is installed or not", i+1);
+        sprintf (label, "Enable usb hub #%d (USB%d)", i+1, i+1);
+        bx_options.usb[i].Oenabled = new bx_param_bool_c (
+                BXP_USBx_ENABLED(i+1),
+                strdup(name), 
+                strdup(descr), 
+                (i==0)?1 : 0);  // only enable the first by default
+        bx_options.usb[i].Oioaddr = new bx_param_num_c (
+                BXP_USBx_IOADDR(i+1),
+                "usb:ioaddr",
+                "I/O base adress of USB hub",
+                0, 0xffe0,
+                (i==0)?0xff80 : 0);
+        bx_options.usb[i].Oirq = new bx_param_num_c (
+                BXP_USBx_IRQ(i+1),
+                "usb:irq",
+                "IRQ used by USB hub",
+                0, 15,
+                (i==0)?10 : 0);
+        deplist = new bx_list_c (BXP_NULL, 2);
+        deplist->add (bx_options.usb[i].Oioaddr);
+        deplist->add (bx_options.usb[i].Oirq);
+        bx_options.usb[i].Oenabled->set_dependent_list (deplist);
+        // add to menu
+        *par_ser_ptr++ = bx_options.usb[i].Oenabled;
+        *par_ser_ptr++ = bx_options.usb[i].Oioaddr;
+        *par_ser_ptr++ = bx_options.usb[i].Oirq;
+
+        bx_options.usb[i].Oioaddr->set_ask_format ("Enter new ioaddr: [0x%x] ");
+        bx_options.usb[i].Oioaddr->set_label ("I/O Address");
+        bx_options.usb[i].Oioaddr->set_base (16);
+        bx_options.usb[i].Oenabled->set_label (strdup(label));
+        bx_options.usb[i].Oirq->set_label ("USB IRQ");
+        bx_options.usb[i].Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+  }
+  // add final NULL at the end, and build the menu
+  *par_ser_ptr = NULL;
+  menu = new bx_list_c (BXP_MENU_SERIAL_PARALLEL,
+          "Serial and Parallel Port Options",
+          "serial_parallel_menu",
+          par_ser_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+  bx_options.rom.Opath = new bx_param_filename_c (BXP_ROM_PATH,
+      "romimage",
+      "Pathname of ROM image to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.rom.Opath->set_format ("Name of ROM BIOS image: %s");
+  bx_options.rom.Oaddress = new bx_param_num_c (BXP_ROM_ADDRESS,
+      "romaddr",
+      "The address at which the ROM image should be loaded",
+      0, BX_MAX_BIT32U, 
+      0xf0000);
+  bx_options.rom.Oaddress->set_base (16);
+#if BX_WITH_WX
+  bx_options.rom.Opath->set_label ("ROM BIOS image");
+  bx_options.rom.Oaddress->set_label ("ROM BIOS address");
+#else
+  bx_options.rom.Oaddress->set_format ("ROM BIOS address: 0x%05x");
+#endif
+
+  bx_options.optrom[0].Opath = new bx_param_filename_c (BXP_OPTROM1_PATH,
+      "optional romimage #1",
+      "Pathname of optional ROM image #1 to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.optrom[0].Opath->set_format ("Name of optional ROM image #1 : %s");
+  bx_options.optrom[0].Oaddress = new bx_param_num_c (BXP_OPTROM1_ADDRESS,
+      "optional romaddr #1",
+      "The address at which the optional ROM image #1 should be loaded",
+      0, BX_MAX_BIT32U, 
+      0);
+  bx_options.optrom[0].Oaddress->set_base (16);
+#if BX_WITH_WX
+  bx_options.optrom[0].Opath->set_label ("Optional ROM image #1");
+  bx_options.optrom[0].Oaddress->set_label ("Address");
+#else
+  bx_options.optrom[0].Oaddress->set_format ("optional ROM #1 address: 0x%05x");
+#endif
+
+  bx_options.optrom[1].Opath = new bx_param_filename_c (BXP_OPTROM2_PATH,
+      "optional romimage #2",
+      "Pathname of optional ROM image #2 to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.optrom[1].Opath->set_format ("Name of optional ROM image #2 : %s");
+  bx_options.optrom[1].Oaddress = new bx_param_num_c (BXP_OPTROM2_ADDRESS,
+      "optional romaddr #2",
+      "The address at which the optional ROM image #2 should be loaded",
+      0, BX_MAX_BIT32U, 
+      0);
+  bx_options.optrom[1].Oaddress->set_base (16);
+#if BX_WITH_WX
+  bx_options.optrom[1].Opath->set_label ("Optional ROM image #2");
+  bx_options.optrom[1].Oaddress->set_label ("Address");
+#else
+  bx_options.optrom[1].Oaddress->set_format ("optional ROM #2 address: 0x%05x");
+#endif
+
+  bx_options.optrom[2].Opath = new bx_param_filename_c (BXP_OPTROM3_PATH,
+      "optional romimage #3",
+      "Pathname of optional ROM image #3 to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.optrom[2].Opath->set_format ("Name of optional ROM image #3 : %s");
+  bx_options.optrom[2].Oaddress = new bx_param_num_c (BXP_OPTROM3_ADDRESS,
+      "optional romaddr #3",
+      "The address at which the optional ROM image #3 should be loaded",
+      0, BX_MAX_BIT32U, 
+      0);
+  bx_options.optrom[2].Oaddress->set_base (16);
+#if BX_WITH_WX
+  bx_options.optrom[2].Opath->set_label ("Optional ROM image #3");
+  bx_options.optrom[2].Oaddress->set_label ("Address");
+#else
+  bx_options.optrom[2].Oaddress->set_format ("optional ROM #3 address: 0x%05x");
+#endif
+
+  bx_options.optrom[3].Opath = new bx_param_filename_c (BXP_OPTROM4_PATH,
+      "optional romimage #4",
+      "Pathname of optional ROM image #4 to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.optrom[3].Opath->set_format ("Name of optional ROM image #4 : %s");
+  bx_options.optrom[3].Oaddress = new bx_param_num_c (BXP_OPTROM4_ADDRESS,
+      "optional romaddr #4",
+      "The address at which the optional ROM image #4 should be loaded",
+      0, BX_MAX_BIT32U, 
+      0);
+  bx_options.optrom[3].Oaddress->set_base (16);
+#if BX_WITH_WX
+  bx_options.optrom[3].Opath->set_label ("Optional ROM image #4");
+  bx_options.optrom[3].Oaddress->set_label ("Address");
+#else
+  bx_options.optrom[3].Oaddress->set_format ("optional ROM #4 address: 0x%05x");
+#endif
+
+  bx_options.vgarom.Opath = new bx_param_filename_c (BXP_VGA_ROM_PATH,
+      "vgaromimage",
+      "Pathname of VGA ROM image to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.vgarom.Opath->set_format ("Name of VGA BIOS image: %s");
+#if BX_WITH_WX
+  bx_options.vgarom.Opath->set_label ("VGA BIOS image");
+#endif
+  bx_param_c *memory_init_list[] = {
+    bx_options.memory.Osize,
+    bx_options.vgarom.Opath,
+    bx_options.rom.Opath,
+    bx_options.rom.Oaddress,
+    bx_options.optrom[0].Opath,
+    bx_options.optrom[0].Oaddress,
+    bx_options.optrom[1].Opath,
+    bx_options.optrom[1].Oaddress,
+    bx_options.optrom[2].Opath,
+    bx_options.optrom[2].Oaddress,
+    bx_options.optrom[3].Opath,
+    bx_options.optrom[3].Oaddress,
+    NULL
+  };
+  menu = new bx_list_c (BXP_MENU_MEMORY, "Bochs Memory Options", "memmenu", memory_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+  // interface
+  bx_options.Ovga_update_interval = new bx_param_num_c (BXP_VGA_UPDATE_INTERVAL,
+      "VGA Update Interval",
+      "Number of microseconds between VGA updates",
+      1, BX_MAX_BIT32U,
+      30000);
+  bx_options.Ovga_update_interval->set_handler (bx_param_handler);
+  bx_options.Ovga_update_interval->set_runtime_param (1);
+  bx_options.Ovga_update_interval->set_ask_format ("Type a new value for VGA update interval: [%d] ");
+  bx_options.Omouse_enabled = new bx_param_bool_c (BXP_MOUSE_ENABLED,
+      "Enable the mouse",
+      "Controls whether the mouse sends events to the guest. The hardware emulation is always enabled.",
+      0);
+  bx_options.Omouse_enabled->set_handler (bx_param_handler);
+  bx_options.Omouse_enabled->set_runtime_param (1);
+  bx_options.Oips = new bx_param_num_c (BXP_IPS, 
+      "Emulated instructions per second (IPS)",
+      "Emulated instructions per second, used to calibrate bochs emulated time with wall clock time.",
+      1, BX_MAX_BIT32U,
+      500000);
+  bx_options.Otext_snapshot_check = new bx_param_bool_c (BXP_TEXT_SNAPSHOT_CHECK,
+      "Enable panic for use in bochs testing",
+      "Enable panic when text on screen matches snapchk.txt.\nUseful for regression testing.\nIn win32, turns off CR/LF in snapshots and cuts.",
+      0);
+  bx_options.Oprivate_colormap = new bx_param_bool_c (BXP_PRIVATE_COLORMAP,
+      "Use a private colormap",
+      "Request that the GUI create and use it's own non-shared colormap. This colormap will be used when in the bochs window. If not enabled, a shared colormap scheme may be used. Not implemented on all GUI's.",
+      0);
+#if BX_WITH_AMIGAOS
+  bx_options.Ofullscreen = new bx_param_bool_c (BXP_FULLSCREEN,
+      "Use full screen mode",
+      "When enabled, bochs occupies the whole screen instead of just a window.",
+      0);
+  bx_options.Oscreenmode = new bx_param_string_c (BXP_SCREENMODE,
+      "Screen mode name",
+      "Screen mode name",
+      "", BX_PATHNAME_LEN);
+  bx_options.Oscreenmode->set_handler (bx_param_string_handler);
+#endif
+  static char *config_interface_list[] = {
+    "textconfig",
+#if BX_WITH_WX
+    "wx",
+#endif
+    NULL
+  };
+  bx_options.Osel_config = new bx_param_enum_c (
+    BXP_SEL_CONFIG_INTERFACE,
+    "Configuration interface",
+    "Select configuration interface",
+    config_interface_list,
+    0,
+    0);
+  bx_options.Osel_config->set_by_name (BX_DEFAULT_CONFIG_INTERFACE);
+  bx_options.Osel_config->set_ask_format ("Choose which configuration interface to use: [%s] ");
+  // this is a list of gui libraries that are known to be available at
+  // compile time.  The one that is listed first will be the default,
+  // which is used unless the user overrides it on the command line or
+  // in a configuration file.
+  static char *display_library_list[] = {
+#if BX_WITH_X11
+    "x",
+#endif
+#if BX_WITH_WIN32
+    "win32",
+#endif
+#if BX_WITH_CARBON
+    "carbon",
+#endif
+#if BX_WITH_BEOS
+    "beos",
+#endif
+#if BX_WITH_MACOS
+    "macos",
+#endif
+#if BX_WITH_AMIGAOS
+    "amigaos",
+#endif
+#if BX_WITH_SDL
+    "sdl",
+#endif
+#if BX_WITH_SVGA
+    "svga",
+#endif
+#if BX_WITH_TERM
+    "term",
+#endif
+#if BX_WITH_RFB
+    "rfb",
+#endif
+#if BX_WITH_WX
+    "wx",
+#endif
+#if BX_WITH_NOGUI
+    "nogui",
+#endif
+    NULL
+  };
+  bx_options.Osel_displaylib = new bx_param_enum_c (BXP_SEL_DISPLAY_LIBRARY,
+    "VGA Display Library",
+    "Select VGA Display Library",
+    display_library_list,
+    0,
+    0);
+  bx_options.Osel_displaylib->set_by_name (BX_DEFAULT_DISPLAY_LIBRARY);
+  bx_options.Osel_displaylib->set_ask_format ("Choose which library to use for the Bochs display: [%s] ");
+  bx_param_c *interface_init_list[] = {
+    bx_options.Osel_config,
+    bx_options.Osel_displaylib,
+    bx_options.Ovga_update_interval,
+    bx_options.Omouse_enabled,
+    bx_options.Oips,
+    bx_options.Oprivate_colormap,
+#if BX_WITH_AMIGAOS
+    bx_options.Ofullscreen,
+    bx_options.Oscreenmode,
+#endif
+    NULL
+  };
+  menu = new bx_list_c (BXP_MENU_INTERFACE, "Bochs Interface Menu", "intfmenu", interface_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+  // NE2K options
+  bx_options.ne2k.Opresent = new bx_param_bool_c (BXP_NE2K_PRESENT,
+      "Enable NE2K NIC emulation",
+      "Enables the NE2K NIC emulation",
+      0);
+  bx_options.ne2k.Oioaddr = new bx_param_num_c (BXP_NE2K_IOADDR,
+      "NE2K I/O Address",
+      "I/O base address of the emulated NE2K device",
+      0, 0xffff,
+      0x240);
+  bx_options.ne2k.Oioaddr->set_base (16);
+  bx_options.ne2k.Oirq = new bx_param_num_c (BXP_NE2K_IRQ,
+      "NE2K Interrupt",
+      "IRQ used by the NE2K device",
+      0, 15,
+      9);
+  bx_options.ne2k.Oirq->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+  bx_options.ne2k.Omacaddr = new bx_param_string_c (BXP_NE2K_MACADDR,
+      "MAC Address",
+      "MAC address of the NE2K device. Don't use an address of a machine on your net.",
+      "\xfe\xfd\xde\xad\xbe\xef", 6);
+  bx_options.ne2k.Omacaddr->get_options ()->set (bx_options.ne2k.Omacaddr->RAW_BYTES);
+  bx_options.ne2k.Omacaddr->set_separator (':');
+  static char *eth_module_list[] = {
+    "null",
+#if defined(ETH_LINUX)
+    "linux",
+#endif
+#if HAVE_ETHERTAP
+    "tap",
+#endif
+#if HAVE_TUNTAP
+    "tuntap",
+#endif
+#if defined(ETH_WIN32)
+    "win32",
+#endif
+#if defined(ETH_FBSD)
+    "fbsd",
+#endif
+#ifdef ETH_ARPBACK
+    "arpback",
+#endif
+    NULL
+  };
+  bx_options.ne2k.Oethmod = new bx_param_enum_c (BXP_NE2K_ETHMOD,
+      "Ethernet module",
+      "Module used for the connection to the real net.",
+       eth_module_list,
+       0,
+       0);
+  bx_options.ne2k.Oethmod->set_by_name ("null");
+  bx_options.ne2k.Oethdev = new bx_param_string_c (BXP_NE2K_ETHDEV,
+      "Ethernet device",
+      "Device used for the connection to the real net. This is only valid if an ethernet module other than 'null' is used.",
+      "xl0", BX_PATHNAME_LEN);
+  bx_options.ne2k.Oscript = new bx_param_string_c (BXP_NE2K_SCRIPT,
+      "Device configuration script",
+      "Name of the script that is executed after Bochs initializes the network interface (optional).",
+      "none", BX_PATHNAME_LEN);
+#if !BX_WITH_WX
+  bx_options.ne2k.Oscript->set_ask_format ("Enter new script name, or 'none': [%s] ");
+#endif
+  bx_param_c *ne2k_init_list[] = {
+    bx_options.ne2k.Opresent,
+    bx_options.ne2k.Oioaddr,
+    bx_options.ne2k.Oirq,
+    bx_options.ne2k.Omacaddr,
+    bx_options.ne2k.Oethmod,
+    bx_options.ne2k.Oethdev,
+    bx_options.ne2k.Oscript,
+    NULL
+  };
+  menu = new bx_list_c (BXP_NE2K, "NE2K Configuration", "", ne2k_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+  bx_param_c **ne2k_dependent_list = &ne2k_init_list[1];
+  bx_options.ne2k.Opresent->set_dependent_list (
+      new bx_list_c (BXP_NULL, "", "", ne2k_dependent_list));
+  bx_options.ne2k.Opresent->set_handler (bx_param_handler);
+  bx_options.ne2k.Opresent->set (0);
+
+  // SB16 options
+  bx_options.sb16.Opresent = new bx_param_bool_c (BXP_SB16_PRESENT,
+      "Enable SB16 emulation",
+      "Enables the SB16 emulation",
+      0);
+  bx_options.sb16.Omidifile = new bx_param_filename_c (BXP_SB16_MIDIFILE,
+      "MIDI file",
+      "The filename is where the MIDI data is sent. This can be device or just a file.",
+      "", BX_PATHNAME_LEN);
+  bx_options.sb16.Owavefile = new bx_param_filename_c (BXP_SB16_WAVEFILE,
+      "Wave file",
+      "This is the device/file where the wave output is stored",
+      "", BX_PATHNAME_LEN);
+  bx_options.sb16.Ologfile = new bx_param_filename_c (BXP_SB16_LOGFILE,
+      "Log file",
+      "The file to write the SB16 emulator messages to.",
+      "", BX_PATHNAME_LEN);
+  bx_options.sb16.Omidimode = new bx_param_num_c (BXP_SB16_MIDIMODE,
+      "Midi mode",
+      "Controls the MIDI output format.",
+      0, 3,
+      0);
+  bx_options.sb16.Owavemode = new bx_param_num_c (BXP_SB16_WAVEMODE,
+      "Wave mode",
+      "Controls the wave output format.",
+      0, 3,
+      0);
+  bx_options.sb16.Ologlevel = new bx_param_num_c (BXP_SB16_LOGLEVEL,
+      "Log mode",
+      "Controls how verbose the SB16 emulation is (0 = no log, 5 = all errors and infos).",
+      0, 5,
+      0);
+  bx_options.sb16.Odmatimer = new bx_param_num_c (BXP_SB16_DMATIMER,
+      "DMA timer",
+      "Microseconds per second for a DMA cycle.",
+      0, BX_MAX_BIT32U,
+      0);
+
+#if BX_WITH_WX
+  bx_options.sb16.Omidimode->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+  bx_options.sb16.Owavemode->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+  bx_options.sb16.Ologlevel->set_options (bx_param_num_c::USE_SPIN_CONTROL);
+#endif
+  bx_param_c *sb16_init_list[] = {
+    bx_options.sb16.Opresent,
+    bx_options.sb16.Omidimode,
+    bx_options.sb16.Omidifile,
+    bx_options.sb16.Owavemode,
+    bx_options.sb16.Owavefile,
+    bx_options.sb16.Ologlevel,
+    bx_options.sb16.Ologfile,
+    bx_options.sb16.Odmatimer,
+    NULL
+  };
+  menu = new bx_list_c (BXP_SB16, "SB16 Configuration", "", sb16_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+  // sb16_dependent_list is a null-terminated list including all the
+  // sb16 fields except for the "present" field.  These will all be enabled/
+  // disabled according to the value of the present field.
+  bx_param_c **sb16_dependent_list = &sb16_init_list[1];
+  bx_options.sb16.Opresent->set_dependent_list (
+      new bx_list_c (BXP_NULL, "", "", sb16_dependent_list));
+
+  bx_options.log.Ofilename = new bx_param_filename_c (BXP_LOG_FILENAME,
+      "Log filename",
+      "Pathname of bochs log file",
+      "-", BX_PATHNAME_LEN);
+  bx_options.log.Ofilename->set_ask_format ("Enter log filename: [%s] ");
+
+  bx_options.log.Oprefix = new bx_param_string_c (BXP_LOG_PREFIX,
+      "Log output prefix",
+      "Prefix prepended to log output",
+      "%t%e%d", BX_PATHNAME_LEN);
+  bx_options.log.Oprefix->set_ask_format ("Enter log prefix: [%s] ");
+
+  bx_options.log.Odebugger_filename = new bx_param_filename_c (BXP_DEBUGGER_LOG_FILENAME,
+      "Debugger Log filename",
+      "Pathname of debugger log file",
+      "-", BX_PATHNAME_LEN);
+  bx_options.log.Odebugger_filename->set_ask_format ("Enter debugger log filename: [%s] ");
+
+  // loader
+  bx_options.load32bitOSImage.OwhichOS = new bx_param_enum_c (BXP_LOAD32BITOS_WHICH,
+      "Which operating system?",
+      "Which OS to boot",
+      loader_os_names,
+#ifdef BX_USE_VMX
+         Load32bitOSLinux,
+#else
+      Load32bitOSNone,
+#endif
+      Load32bitOSNone);
+  bx_options.load32bitOSImage.Opath = new bx_param_filename_c (BXP_LOAD32BITOS_PATH,
+      "Pathname of OS to load",
+      "Pathname of the 32-bit OS to load",
+      "", BX_PATHNAME_LEN);
+  bx_options.load32bitOSImage.Oiolog = new bx_param_filename_c (BXP_LOAD32BITOS_IOLOG,
+      "Pathname of I/O log file",
+      "I/O logfile used for initializing the hardware",
+      "", BX_PATHNAME_LEN);
+  bx_options.load32bitOSImage.Oinitrd = new bx_param_filename_c (BXP_LOAD32BITOS_INITRD,
+      "Pathname of initrd",
+      "Pathname of the initial ramdisk",
+      "", BX_PATHNAME_LEN);
+  bx_param_c *loader_init_list[] = {
+    bx_options.load32bitOSImage.OwhichOS,
+    bx_options.load32bitOSImage.Opath,
+    bx_options.load32bitOSImage.Oiolog,
+    bx_options.load32bitOSImage.Oinitrd,
+    NULL
+  };
+  bx_options.load32bitOSImage.OwhichOS->set_format ("os=%s");
+  bx_options.load32bitOSImage.Opath->set_format ("path=%s");
+  bx_options.load32bitOSImage.Oiolog->set_format ("iolog=%s");
+  bx_options.load32bitOSImage.Oinitrd->set_format ("initrd=%s");
+  bx_options.load32bitOSImage.OwhichOS->set_ask_format ("Enter OS to load: [%s] ");
+  bx_options.load32bitOSImage.Opath->set_ask_format ("Enter pathname of OS: [%s]");
+  bx_options.load32bitOSImage.Oiolog->set_ask_format ("Enter pathname of I/O log: [%s] ");
+  bx_options.load32bitOSImage.Oinitrd->set_ask_format ("Enter pathname of initrd: [%s] ");
+  menu = new bx_list_c (BXP_LOAD32BITOS, "32-bit OS Loader", "", loader_init_list);
+  menu->get_options ()->set (menu->SERIES_ASK);
+  bx_options.load32bitOSImage.OwhichOS->set_handler (bx_param_handler);
+#ifdef BX_USE_VMX
+  bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSLinux);
+#else
+  bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSNone);
+#endif
+
+  // clock
+  bx_options.clock.Otime0 = new bx_param_num_c (BXP_CLOCK_TIME0,
+      "clock:time0",
+      "Initial time for Bochs CMOS clock, used if you really want two runs to be identical",
+      0, BX_MAX_BIT32U,
+      BX_CLOCK_TIME0_LOCAL);
+  bx_options.clock.Osync = new bx_param_enum_c (BXP_CLOCK_SYNC,
+      "clock:sync",
+      "Host to guest time synchronization method",
+      clock_sync_names,
+      BX_CLOCK_SYNC_NONE,
+      BX_CLOCK_SYNC_NONE);
+  bx_param_c *clock_init_list[] = {
+    bx_options.clock.Osync,
+    bx_options.clock.Otime0,
+    NULL
+  };
+#if !BX_WITH_WX
+  bx_options.clock.Osync->set_format ("sync=%s");
+  bx_options.clock.Otime0->set_format ("initial time=%d");
+#endif
+  bx_options.clock.Otime0->set_ask_format ("Enter Initial CMOS time (1:localtime, 2:utc, other:time in seconds): [%d] ");
+  bx_options.clock.Osync->set_ask_format ("Enter Synchronisation method: [%s] ");
+  bx_options.clock.Otime0->set_label ("Initial CMOS time for Bochs\n(1:localtime, 2:utc, other:time in seconds)");
+  bx_options.clock.Osync->set_label ("Synchronisation method");
+  menu = new bx_list_c (BXP_CLOCK, "Clock parameters", "", clock_init_list);
+  menu->get_options ()->set (menu->SERIES_ASK);
+
+  // other
+  bx_options.Okeyboard_serial_delay = new bx_param_num_c (BXP_KBD_SERIAL_DELAY,
+      "Keyboard serial delay",
+      "Approximate time in microseconds that it takes one character to be transfered from the keyboard to controller over the serial path.",
+      1, BX_MAX_BIT32U,
+      20000);
+  bx_options.Okeyboard_paste_delay = new bx_param_num_c (BXP_KBD_PASTE_DELAY,
+      "Keyboard paste delay",
+      "Approximate time in microseconds between attemps to paste characters to the keyboard controller.",
+      1000, BX_MAX_BIT32U,
+      100000);
+  bx_options.Okeyboard_paste_delay->set_handler (bx_param_handler);
+  bx_options.Okeyboard_paste_delay->set_runtime_param (1);
+  bx_options.Ofloppy_command_delay = new bx_param_num_c (BXP_FLOPPY_CMD_DELAY,
+      "Floppy command delay",
+      "Time in microseconds to wait before completing some floppy commands such as read/write/seek/etc, which normally have a delay associated.  This used to be hardwired to 50,000 before.",
+      1, BX_MAX_BIT32U,
+      50000);
+  bx_options.Oi440FXSupport = new bx_param_bool_c (BXP_I440FX_SUPPORT,
+      "PCI i440FX Support",
+      "Controls whether to emulate the i440FX PCI chipset",
+      0);
+  bx_options.cmos.OcmosImage = new bx_param_bool_c (BXP_CMOS_IMAGE,
+      "Use a CMOS image",
+      "Controls the usage of a CMOS image",
+      0);
+  bx_options.cmos.Opath = new bx_param_filename_c (BXP_CMOS_PATH,
+      "Pathname of CMOS image",
+      "Pathname of CMOS image",
+      "", BX_PATHNAME_LEN);
+  deplist = new bx_list_c (BXP_NULL, 1);
+  deplist->add (bx_options.cmos.Opath);
+  bx_options.cmos.OcmosImage->set_dependent_list (deplist);
+
+  // Keyboard mapping
+  bx_options.keyboard.OuseMapping = new bx_param_bool_c(BXP_KEYBOARD_USEMAPPING,
+      "Use keyboard mapping",
+      "Controls whether to use the keyboard mapping feature",
+      0);
+  bx_options.keyboard.Okeymap = new bx_param_filename_c (BXP_KEYBOARD_MAP,
+      "Keymap filename",
+      "Pathname of the keymap file used",
+      "", BX_PATHNAME_LEN);
+  deplist = new bx_list_c (BXP_NULL, 1);
+  deplist->add (bx_options.keyboard.Okeymap);
+  bx_options.keyboard.OuseMapping->set_dependent_list (deplist);
+
+ // Keyboard type
+  bx_options.Okeyboard_type = new bx_param_enum_c (BXP_KBD_TYPE,
+      "Keyboard type",
+      "Keyboard type reported by the 'identify keyboard' command",
+      keyboard_type_names,
+      BX_KBD_MF_TYPE,
+      BX_KBD_XT_TYPE);
+  bx_options.Okeyboard_type->set_ask_format ("Enter keyboard type: [%s] ");
+
+  // Userbutton shortcut
+  bx_options.Ouser_shortcut = new bx_param_string_c (BXP_USER_SHORTCUT,
+      "Userbutton shortcut",
+      "Defines the keyboard shortcut to be sent when you press the 'user' button in the headerbar.",
+      "none", 16);
+
+  // GDB stub
+  bx_options.gdbstub.port = 1234;
+  bx_options.gdbstub.text_base = 0;
+  bx_options.gdbstub.data_base = 0;
+  bx_options.gdbstub.bss_base = 0;
+
+  bx_param_c *keyboard_init_list[] = {
+      bx_options.Okeyboard_serial_delay,
+      bx_options.Okeyboard_paste_delay,
+      bx_options.keyboard.OuseMapping,
+      bx_options.keyboard.Okeymap,
+      bx_options.Okeyboard_type,
+      bx_options.Ouser_shortcut,
+      NULL
+  };
+  menu = new bx_list_c (BXP_MENU_KEYBOARD, "Configure Keyboard", "", keyboard_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+  bx_param_c *other_init_list[] = {
+      bx_options.Ofloppy_command_delay,
+      bx_options.Oi440FXSupport,
+      bx_options.cmos.OcmosImage,
+      bx_options.cmos.Opath,
+      SIM->get_param (BXP_CLOCK),
+      SIM->get_param (BXP_LOAD32BITOS),
+      NULL
+  };
+  menu = new bx_list_c (BXP_MENU_MISC, "Configure Everything Else", "", other_init_list);
+  menu->get_options ()->set (menu->SHOW_PARENT);
+
+#if BX_WITH_WX
+  bx_param_c *other_init_list2[] = {
+//    bx_options.Osel_config,
+//    bx_options.Osel_displaylib,
+      bx_options.Ovga_update_interval,
+      bx_options.log.Oprefix,
+      bx_options.Omouse_enabled,
+      bx_options.OfloppySigCheck,
+      bx_options.Ofloppy_command_delay,
+      bx_options.OnewHardDriveSupport,
+      bx_options.Oprivate_colormap,
+#if BX_WITH_AMIGAOS
+      bx_options.Ofullscreen,
+      bx_options.Oscreenmode,
+#endif
+      bx_options.Oi440FXSupport,
+      bx_options.cmos.OcmosImage,
+      bx_options.cmos.Opath,
+      NULL
+  };
+  menu = new bx_list_c (BXP_MENU_MISC_2, "Other options", "", other_init_list2);
+#endif
+}
+
+void bx_reset_options ()
+{
+  // drives
+  bx_options.floppya.Opath->reset();
+  bx_options.floppya.Odevtype->reset();
+  bx_options.floppya.Otype->reset();
+  bx_options.floppya.Ostatus->reset();
+  bx_options.floppyb.Opath->reset();
+  bx_options.floppyb.Odevtype->reset();
+  bx_options.floppyb.Otype->reset();
+  bx_options.floppyb.Ostatus->reset();
+
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    bx_options.ata[channel].Opresent->reset();
+    bx_options.ata[channel].Oioaddr1->reset();
+    bx_options.ata[channel].Oioaddr2->reset();
+    bx_options.ata[channel].Oirq->reset();
+
+    for (Bit8u slave=0; slave<2; slave++) {
+      bx_options.atadevice[channel][slave].Opresent->reset();
+      bx_options.atadevice[channel][slave].Otype->reset();
+      bx_options.atadevice[channel][slave].Omode->reset();
+      bx_options.atadevice[channel][slave].Opath->reset();
+      bx_options.atadevice[channel][slave].Ocylinders->reset();
+      bx_options.atadevice[channel][slave].Oheads->reset();
+      bx_options.atadevice[channel][slave].Ospt->reset();
+      bx_options.atadevice[channel][slave].Ostatus->reset();
+      bx_options.atadevice[channel][slave].Omodel->reset();
+      bx_options.atadevice[channel][slave].Obiosdetect->reset();
+      bx_options.atadevice[channel][slave].Otranslation->reset();
+      }
+    }
+  bx_options.OnewHardDriveSupport->reset();
+
+  // boot & memory
+  bx_options.Obootdrive->reset();
+  bx_options.OfloppySigCheck->reset();
+  bx_options.memory.Osize->reset();
+
+  // standard ports
+  bx_options.com[0].Oenabled->reset();
+  bx_options.com[0].Odev->reset();
+  bx_options.par[0].Oenabled->reset();
+  bx_options.par[0].Ooutfile->reset();
+
+  // rom images
+  bx_options.rom.Opath->reset();
+  bx_options.rom.Oaddress->reset();
+  bx_options.optrom[0].Opath->reset();
+  bx_options.optrom[0].Oaddress->reset();
+  bx_options.optrom[1].Opath->reset();
+  bx_options.optrom[1].Oaddress->reset();
+  bx_options.optrom[2].Opath->reset();
+  bx_options.optrom[2].Oaddress->reset();
+  bx_options.optrom[3].Opath->reset();
+  bx_options.optrom[3].Oaddress->reset();
+  bx_options.vgarom.Opath->reset();
+
+  // interface
+  bx_options.Ovga_update_interval->reset();
+  bx_options.Omouse_enabled->reset();
+  bx_options.Oips->reset();
+  bx_options.Oprivate_colormap->reset();
+#if BX_WITH_AMIGAOS
+  bx_options.Ofullscreen->reset();
+  bx_options.Oscreenmode->reset();
+#endif
+
+  // ne2k
+  bx_options.ne2k.Opresent->reset();
+  bx_options.ne2k.Oioaddr->reset();
+  bx_options.ne2k.Oirq->reset();
+  bx_options.ne2k.Omacaddr->reset();
+  bx_options.ne2k.Oethmod->reset();
+  bx_options.ne2k.Oethdev->reset();
+  bx_options.ne2k.Oscript->reset();
+
+  // SB16
+  bx_options.sb16.Opresent->reset();
+  bx_options.sb16.Omidifile->reset();
+  bx_options.sb16.Owavefile->reset();
+  bx_options.sb16.Ologfile->reset();
+  bx_options.sb16.Omidimode->reset();
+  bx_options.sb16.Owavemode->reset();
+  bx_options.sb16.Ologlevel->reset();
+  bx_options.sb16.Odmatimer->reset();
+
+  // logfile
+  bx_options.log.Ofilename->reset();
+  bx_options.log.Oprefix->reset();
+  bx_options.log.Odebugger_filename->reset();
+
+  // loader
+  bx_options.load32bitOSImage.OwhichOS->reset();
+  bx_options.load32bitOSImage.Opath->reset();
+  bx_options.load32bitOSImage.Oiolog->reset();
+  bx_options.load32bitOSImage.Oinitrd->reset();
+
+  // keyboard
+  bx_options.Okeyboard_serial_delay->reset();
+  bx_options.Okeyboard_paste_delay->reset();
+  bx_options.keyboard.OuseMapping->reset();
+  bx_options.keyboard.Okeymap->reset();
+  bx_options.Okeyboard_type->reset();
+  bx_options.Ouser_shortcut->reset();
+
+  // Clock
+  bx_options.clock.Otime0->reset();
+  bx_options.clock.Osync->reset();
+
+  // other
+  bx_options.Ofloppy_command_delay->reset();
+  bx_options.Oi440FXSupport->reset();
+  bx_options.cmos.OcmosImage->reset();
+  bx_options.cmos.Opath->reset();
+  bx_options.Otext_snapshot_check->reset();
+}
+
+void bx_print_header ()
+{
+  fprintf (stderr, "%s\n", divider);
+  char buffer[128];
+  sprintf (buffer, "Bochs x86 Emulator %s\n", VER_STRING);
+  bx_center_print (stderr, buffer, 72);
+  if (REL_STRING[0]) {
+    sprintf (buffer, "%s\n", REL_STRING);
+    bx_center_print (stderr, buffer, 72);
+  }
+  fprintf (stderr, "%s\n", divider);
+}
+
+#if BX_WITH_CARBON
+/* Original code by Darrell Walisser - dwaliss1@purdue.edu */
+
+static void setupWorkingDirectory (char *path)
+{
+    char parentdir[MAXPATHLEN];
+    char *c;
+    
+    strncpy ( parentdir, path, MAXPATHLEN );
+    c = (char*) parentdir;
+    
+    while (*c != '\0')     /* go to end */
+        c++;
+    
+    while (*c != '/')      /* back up to parent */
+        c--;
+    
+    *c = '\0';             /* cut off last part (binary name) */
+    
+        /* chdir to the binary app's parent */
+        int n;
+        n = chdir (parentdir);
+        if (n) BX_PANIC (("failed to change dir to parent"));
+        /* chdir to the .app's parent */
+        n = chdir ("../../../");
+    if (n) BX_PANIC (("failed to change to ../../.."));
+}
+
+/* Panic button to display fatal errors.
+  Completely self contained, can't rely on carbon.cc being available */
+static void carbonFatalDialog(const char *error, const char *exposition)
+{
+  DialogRef                     alertDialog;
+  CFStringRef                   cfError;
+  CFStringRef                   cfExposition;
+  DialogItemIndex               index;
+  AlertStdCFStringAlertParamRec alertParam = {0};
+  fprintf(stderr, "Entering carbonFatalDialog: %s\n", error);
+  
+  // Init libraries
+  InitCursor();
+  // Assemble dialog
+  cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII);
+  if(exposition != NULL)
+  {
+    cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII);
+  }
+  else { cfExposition = NULL; }
+  alertParam.version       = kStdCFStringAlertVersionOne;
+  alertParam.defaultText   = CFSTR("Quit");
+  alertParam.position      = kWindowDefaultPosition;
+  alertParam.defaultButton = kAlertStdAlertOKButton;
+  // Display Dialog
+  CreateStandardAlert(
+    kAlertStopAlert,
+    cfError,
+    cfExposition,       /* can be NULL */
+    &alertParam,             /* can be NULL */
+    &alertDialog);
+  RunStandardAlert( alertDialog, NULL, &index);
+  // Cleanup
+  CFRelease( cfError );
+  if( cfExposition != NULL ) { CFRelease( cfExposition ); }
+}
+#endif
+
+int bxmain () {
+#ifdef HAVE_LOCALE_H
+  // Initialize locale (for isprint() and other functions)
+  setlocale (LC_ALL, "");
+#endif
+  bx_user_quit = 0;
+  bx_init_siminterface ();   // create the SIM object
+
+  static jmp_buf context;
+  if (setjmp (context) == 0) {
+    SIM->set_quit_context (&context);
+    if (bx_init_main (bx_startup_flags.argc, bx_startup_flags.argv) < 0) 
+      return 0;
+    // read a param to decide which config interface to start.
+    // If one exists, start it.  If not, just begin.
+    bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+    char *ci_name = ci_param->get_choice (ci_param->get ());
+    if (!strcmp(ci_name, "textconfig")) {
+      init_text_config_interface ();   // in textconfig.h
+    }
+#if BX_WITH_WX
+    else if (!strcmp(ci_name, "wx")) {
+      PLUG_load_plugin(wx, PLUGTYPE_CORE);
+    }
+#endif
+    else {
+      BX_PANIC (("unsupported configuration interface '%s'", ci_name));
+    }
+    int status = SIM->configuration_interface (ci_name, CI_START);
+    if (status == CI_ERR_NO_TEXT_CONSOLE)
+      BX_PANIC (("Bochs needed the text console, but it was not usable"));
+    // user quit the config interface, so just quit
+  } else {
+    // quit via longjmp
+  }
+}
+
+// normal main function, presently in for all cases except for
+// wxWindows under win32.
+int main (int argc, char *argv[])
+{
+  bx_startup_flags.argc = argc;
+  bx_startup_flags.argv = argv;
+#if BX_WITH_SDL && defined(WIN32)
+  // if SDL/win32, try to create a console window.
+  RedirectIOToConsole ();
+#endif
+  return bxmain ();
+}
+
+void
+print_usage ()
+{
+  fprintf(stderr, 
+    "Usage: bochs [flags] [bochsrc options]\n\n"
+    "  -n               no configuration file\n"
+    "  -f configfile    specify configuration file\n"
+    "  -q               quick start (skip configuration interface)\n"
+    "  --help           display this help and exit\n\n"
+    "For information on Bochs configuration file arguments, see the\n"
+#if (!defined(WIN32)) && !BX_WITH_MACOS
+    "bochsrc section in the user documentation or the man page of bochsrc.\n");
+#else
+    "bochsrc section in the user documentation.\n");
+#endif
+}
+
+#ifdef BX_USE_VMX
+int domid = -1;
+unsigned long megabytes = 0;
+#endif
+int
+bx_init_main (int argc, char *argv[])
+{
+  // To deal with initialization order problems inherent in C++, use the macros
+  // SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog" in all
+  // constructors or functions called by constructors.  The macros test for
+  // NULL and create the object if necessary, then return it.  Ensure that io
+  // and genlog get created, by making one reference to each macro right here.
+  // All other code can reference io and genlog directly.  Because these
+  // objects are required for logging, and logging is so fundamental to
+  // knowing what the program is doing, they are never free()d.
+  SAFE_GET_IOFUNC();  // never freed
+  SAFE_GET_GENLOG();  // never freed
+
+  // initalization must be done early because some destructors expect
+  // the bx_options to exist by the time they are called.
+  bx_init_bx_dbg ();
+  bx_init_options ();
+
+  bx_print_header ();
+
+#ifdef BX_USE_VMX
+  xc_handle = xc_interface_open();
+  SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+#else
+  SIM->get_param_enum(BXP_BOCHS_START)->set (BX_RUN_START);
+#endif
+
+  // interpret the args that start with -, like -q, -f, etc.
+  int arg = 1, load_rcfile=1;
+  while (arg < argc) {
+    // parse next arg
+    if (!strcmp ("--help", argv[arg]) || !strncmp ("-h", argv[arg], 2)) {
+      print_usage();
+      SIM->quit_sim (0);
+    }
+    else if (!strcmp ("-n", argv[arg])) {
+      load_rcfile = 0;
+    }
+    else if (!strcmp ("-q", argv[arg])) {
+      SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+    }
+    else if (!strcmp ("-f", argv[arg])) {
+      if (++arg >= argc) BX_PANIC(("-f must be followed by a filename"));
+      else bochsrc_filename = argv[arg];
+    }
+    else if (!strcmp ("-qf", argv[arg])) {
+      SIM->get_param_enum(BXP_BOCHS_START)->set (BX_QUICK_START);
+      if (++arg >= argc) BX_PANIC(("-qf must be followed by a filename"));
+      else bochsrc_filename = argv[arg];
+    }
+#ifdef BX_USE_VMX
+    else if (!strcmp ("-p", argv[arg])) {
+    //get the polling port
+    extern int ioreq_port;
+      if (++arg >= argc) BX_PANIC(("-p must be followed by a polling port"));
+      else sscanf(argv[arg], "%d", &ioreq_port);
+    }
+    else if (!strcmp ("-d", argv[arg])) {
+    //get the domain id
+      if (++arg >= argc) BX_PANIC(("-d must be followed by domainid"));
+      else sscanf(argv[arg], "%d", &domid);
+    }
+    else if (!strcmp ("-m", argv[arg])) {
+    //get the maxmem
+      if (++arg >= argc) 
+                 BX_PANIC(("-m must be followed by maxmem in megabytes"));
+      else sscanf(argv[arg], "%d", &megabytes);
+    }
+
+#endif
+    else if (argv[arg][0] == '-') {
+      print_usage();
+      BX_PANIC (("command line arg '%s' was not understood", argv[arg]));
+    }
+    else {
+      // the arg did not start with -, so stop interpreting flags
+      break;
+    }
+    arg++;
+  }
+
+  int norcfile = 1;
+
+  if (load_rcfile) {
+    /* parse configuration file and command line arguments */
+#ifdef WIN32
+    if (bochsrc_filename != NULL) {
+      lstrcpy(bx_startup_flags.initial_dir, bochsrc_filename);
+    } else {
+      bx_startup_flags.initial_dir[0] = 0;
+    }
+#endif
+    if (bochsrc_filename == NULL) bochsrc_filename = bx_find_bochsrc ();
+    if (bochsrc_filename)
+      norcfile = bx_read_configuration (bochsrc_filename);
+  }
+
+  // parse the rest of the command line.  This is done after reading the
+  // configuration file so that the command line arguments can override
+  // the settings from the file.
+  if (bx_parse_cmdline (arg, argc, argv)) {
+    BX_PANIC(("There were errors while parsing the command line"));
+    return -1;
+  }
+  // initialize plugin system. This must happen before we attempt to
+  // load any modules.
+  plugin_startup();
+  return 0;
+}
+
+bx_bool load_and_init_display_lib () {
+  if (bx_gui != NULL) {
+    // bx_gui has already been filled in.  This happens when you start
+    // the simulation for the second time.
+    // Also, if you load wxWindows as the configuration interface.  Its
+    // plugin_init will install wxWindows as the bx_gui.
+    return true;
+  }
+  BX_ASSERT (bx_gui == NULL);
+  bx_param_enum_c *ci_param = SIM->get_param_enum (BXP_SEL_CONFIG_INTERFACE);
+  char *ci_name = ci_param->get_choice (ci_param->get ());
+  bx_param_enum_c *gui_param = SIM->get_param_enum(BXP_SEL_DISPLAY_LIBRARY);
+  char *gui_name = gui_param->get_choice (gui_param->get ());
+  if (!strcmp(ci_name, "wx")) {
+    BX_ERROR(("change of the config interface to wx not implemented yet"));
+  }
+  if (!strcmp (gui_name, "wx")) {
+    // they must not have used wx as the configuration interface, or bx_gui
+    // would already be initialized.  Sorry, it doesn't work that way.
+    BX_ERROR (("wxWindows was not used as the configuration interface, so it cannot be used as the display library"));
+    // choose another, hopefully different!
+    gui_param->set (0);
+    gui_name = gui_param->get_choice (gui_param->get ());
+    if (!strcmp (gui_name, "wx")) {
+      BX_PANIC (("no alternative display libraries are available"));
+      return false;
+    }
+    BX_ERROR (("changing display library to '%s' instead", gui_name));
+  }
+#if BX_WITH_NOGUI
+  if (!strcmp (gui_name, "nogui")) 
+    PLUG_load_plugin (nogui, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_WITH_RFB
+  if (!strcmp (gui_name, "rfb")) 
+    PLUG_load_plugin (rfb, PLUGTYPE_OPTIONAL);
+#endif
+#if BX_WITH_X11
+  if (!strcmp (gui_name, "x")) 
+    PLUG_load_plugin (x, PLUGTYPE_OPTIONAL);
+#endif
+
+#if BX_GUI_SIGHANDLER
+  // set the flag for guis requiring a GUI sighandler.
+  // useful when guis are compiled as plugins
+  // only term for now
+  if (!strcmp (gui_name, "term")) {
+    bx_gui_sighandler = 1;
+    }
+#endif
+
+  BX_ASSERT (bx_gui != NULL);
+  return true;
+}
+
+int
+bx_begin_simulation (int argc, char *argv[])
+{
+  // deal with gui selection
+  if (!load_and_init_display_lib ()) {
+    BX_PANIC (("no gui module was loaded"));
+    return 0;
+  }
+#if BX_GDBSTUB
+  // If using gdbstub, it will take control and call
+  // bx_init_hardware() and cpu_loop()
+  bx_gdbstub_init (argc, argv);
+#elif BX_DEBUGGER
+  // If using the debugger, it will take control and call
+  // bx_init_hardware() and cpu_loop()
+  bx_dbg_main(argc, argv);
+#else
+
+  bx_init_hardware();
+
+  if (bx_options.load32bitOSImage.OwhichOS->get ()) {
+    void bx_load32bitOSimagehack(void);
+    bx_load32bitOSimagehack();
+    }
+
+  SIM->set_init_done (1);
+
+  // update headerbar buttons since drive status can change during init
+  bx_gui->update_drive_status_buttons ();
+
+  // The set handler for mouse_enabled does not actually update the gui
+  // until init_done is set.  This forces the set handler to be called,
+  // which sets up the mouse enabled GUI-specific stuff correctly.
+  // Not a great solution but it works. BBD
+  bx_options.Omouse_enabled->set (bx_options.Omouse_enabled->get ());
+
+  if (BX_SMP_PROCESSORS == 1) {
+    // only one processor, run as fast as possible by not messing with
+    // quantums and loops.
+    BX_CPU(0)->cpu_loop(1);
+        // for one processor, the only reason for cpu_loop to return is
+        // that kill_bochs_request was set by the GUI interface.
+  } else {
+    // SMP simulation: do a few instructions on each processor, then switch
+    // to another.  Increasing quantum speeds up overall performance, but
+    // reduces granularity of synchronization between processors.
+    int processor = 0;
+    int quantum = 5;
+    while (1) {
+      // do some instructions in each processor
+      BX_CPU(processor)->cpu_loop(quantum);
+      processor = (processor+1) % BX_SMP_PROCESSORS;
+          if (BX_CPU(0)->kill_bochs_request) 
+            break;
+      if (processor == 0) 
+            BX_TICKN(quantum);
+    }
+  }
+#endif
+  BX_INFO (("cpu loop quit, shutting down simulator"));
+  bx_atexit ();
+  return(0);
+}
+
+
+int
+bx_read_configuration (char *rcfile)
+{
+  // parse rcfile first, then parse arguments in order.
+  BX_INFO (("reading configuration from %s", rcfile));
+  if (parse_bochsrc(rcfile) < 0) {
+    BX_PANIC (("reading from %s failed", rcfile));
+    return -1;
+  }
+  // update log actions
+  for (int level=0; level<N_LOGLEV; level++) {
+    int action = SIM->get_default_log_action (level);
+    io->set_log_action (level, action);
+  }
+  return 0;
+}
+
+int bx_parse_cmdline (int arg, int argc, char *argv[])
+{
+  //if (arg < argc) BX_INFO (("parsing command line arguments"));
+
+  while (arg < argc) {
+    BX_INFO (("parsing arg %d, %s", arg, argv[arg]));
+    parse_line_unformatted("cmdline args", argv[arg]);
+    arg++;
+  }
+  // update log actions
+  for (int level=0; level<N_LOGLEV; level++) {
+    int action = SIM->get_default_log_action (level);
+    io->set_log_action (level, action);
+  }
+  return 0;
+}
+
+  int
+bx_init_hardware()
+{
+  // all configuration has been read, now initialize everything.
+
+  if (SIM->get_param_enum(BXP_BOCHS_START)->get ()==BX_QUICK_START) {
+    for (int level=0; level<N_LOGLEV; level++) {
+      int action = SIM->get_default_log_action (level);
+#if !BX_USE_CONFIG_INTERFACE
+      if (action == ACT_ASK) action = ACT_FATAL;
+#endif
+      io->set_log_action (level, action);
+    }
+  }
+
+  bx_pc_system.init_ips(bx_options.Oips->get ());
+
+  if(bx_options.log.Ofilename->getptr()[0]!='-') {
+    BX_INFO (("using log file %s", bx_options.log.Ofilename->getptr ()));
+    io->init_log(bx_options.log.Ofilename->getptr ());
+  }
+
+  io->set_log_prefix(bx_options.log.Oprefix->getptr());
+
+  // Output to the log file the cpu settings
+  // This will by handy for bug reports
+  BX_INFO(("Bochs x86 Emulator %s", VER_STRING));
+  BX_INFO(("  %s", REL_STRING));
+  BX_INFO(("System configuration"));
+  BX_INFO(("  processors: %d",BX_SMP_PROCESSORS));
+  BX_INFO(("  A20 line support: %s",BX_SUPPORT_A20?"yes":"no"));
+  BX_INFO(("  APIC support: %s",BX_SUPPORT_APIC?"yes":"no"));
+
+#ifndef BX_USE_VMX
+  BX_INFO(("CPU configuration"));
+  BX_INFO(("  level: %d",BX_CPU_LEVEL));
+  BX_INFO(("  fpu support: %s",BX_SUPPORT_FPU?"yes":"no"));
+  BX_INFO(("  paging support: %s, tlb enabled: %s",BX_SUPPORT_PAGING?"yes":"no",BX_USE_TLB?"yes":"no"));
+  BX_INFO(("  mmx support: %s",BX_SUPPORT_MMX?"yes":"no"));
+  BX_INFO(("  sse support: %s",BX_SUPPORT_SSE==2?"2":BX_SUPPORT_SSE==1?"1":"no"));
+  BX_INFO(("  v8086 mode support: %s",BX_SUPPORT_V8086_MODE?"yes":"no"));
+  BX_INFO(("  3dnow! support: %s",BX_SUPPORT_3DNOW?"yes":"no"));
+  BX_INFO(("  PAE support: %s",BX_SupportPAE?"yes":"no"));
+  BX_INFO(("  PGE support: %s",BX_SupportGlobalPages?"yes":"no"));
+  BX_INFO(("  PSE support: %s",BX_SUPPORT_4MEG_PAGES?"yes":"no"));
+  BX_INFO(("  x86-64 support: %s",BX_SUPPORT_X86_64?"yes":"no"));
+  BX_INFO(("  SEP support: %s",BX_SUPPORT_SEP?"yes":"no"));
+  BX_INFO(("Optimization configuration"));
+  BX_INFO(("  Guest2HostTLB support: %s",BX_SupportGuest2HostTLB?"yes":"no"));
+  BX_INFO(("  RepeatSpeedups support: %s",BX_SupportRepeatSpeedups?"yes":"no"));
+  BX_INFO(("  Icache support: %s",BX_SupportICache?"yes":"no"));
+  BX_INFO(("  Host Asm support: %s",BX_SupportHostAsms?"yes":"no"));
+#endif /* BX_USE_VMX */
+
+  // set up memory and CPU objects
+#if BX_SUPPORT_APIC
+  bx_generic_apic_c::reset_all_ids ();
+#endif
+
+#ifndef BX_USE_VMX
+  // Check if there is a romimage
+  if (strcmp(bx_options.rom.Opath->getptr (),"") == 0) {
+    BX_ERROR(("No romimage to load. Is your bochsrc file loaded/valid ?"));
+  }
+
+#if BX_SMP_PROCESSORS==1
+  BX_MEM(0)->init_memory(bx_options.memory.Osize->get () * 1024*1024);
+
+  // First load the optional ROM images
+  if (strcmp(bx_options.optrom[0].Opath->getptr (),"") !=0 )
+    BX_MEM(0)->load_ROM(bx_options.optrom[0].Opath->getptr (), bx_options.optrom[0].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[1].Opath->getptr (),"") !=0 )
+    BX_MEM(0)->load_ROM(bx_options.optrom[1].Opath->getptr (), bx_options.optrom[1].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[2].Opath->getptr (),"") !=0 )
+    BX_MEM(0)->load_ROM(bx_options.optrom[2].Opath->getptr (), bx_options.optrom[2].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[3].Opath->getptr (),"") !=0 )
+    BX_MEM(0)->load_ROM(bx_options.optrom[3].Opath->getptr (), bx_options.optrom[3].Oaddress->get (), 2);
+
+  // Then Load the BIOS and VGABIOS
+  BX_MEM(0)->load_ROM(bx_options.rom.Opath->getptr (), bx_options.rom.Oaddress->get (), 0);
+  BX_MEM(0)->load_ROM(bx_options.vgarom.Opath->getptr (), 0xc0000, 1);
+
+  BX_CPU(0)->init (BX_MEM(0));
+  BX_CPU(0)->set_cpu_id(0);
+#if BX_SUPPORT_APIC
+  BX_CPU(0)->local_apic.set_id (0);
+#endif
+  BX_INSTR_INIT(0);
+  BX_CPU(0)->reset(BX_RESET_HARDWARE);
+#else
+  // SMP initialization
+  bx_mem_array[0] = new BX_MEM_C ();
+  bx_mem_array[0]->init_memory(bx_options.memory.Osize->get () * 1024*1024);
+
+  // First load the optional ROM images
+  if (strcmp(bx_options.optrom[0].Opath->getptr (),"") !=0 )
+    bx_mem_array[0]->load_ROM(bx_options.optrom[0].Opath->getptr (), bx_options.optrom[0].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[1].Opath->getptr (),"") !=0 )
+    bx_mem_array[0]->load_ROM(bx_options.optrom[1].Opath->getptr (), bx_options.optrom[1].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[2].Opath->getptr (),"") !=0 )
+    bx_mem_array[0]->load_ROM(bx_options.optrom[2].Opath->getptr (), bx_options.optrom[2].Oaddress->get (), 2);
+  if (strcmp(bx_options.optrom[3].Opath->getptr (),"") !=0 )
+    bx_mem_array[0]->load_ROM(bx_options.optrom[3].Opath->getptr (), bx_options.optrom[3].Oaddress->get (), 2);
+
+  // Then Load the BIOS and VGABIOS
+  bx_mem_array[0]->load_ROM(bx_options.rom.Opath->getptr (), bx_options.rom.Oaddress->get (), 0);
+  bx_mem_array[0]->load_ROM(bx_options.vgarom.Opath->getptr (), 0xc0000, 1);
+
+  for (int i=0; i<BX_SMP_PROCESSORS; i++) {
+    BX_CPU(i) = new BX_CPU_C;
+    BX_CPU(i)->init (bx_mem_array[0]);
+    // assign apic ID from the index of this loop
+    // if !BX_SUPPORT_APIC, this will not compile.
+    BX_CPU(i)->set_cpu_id(i);
+    BX_CPU(i)->local_apic.set_id (i);
+    BX_INSTR_INIT(i);
+    BX_CPU(i)->reset(BX_RESET_HARDWARE);
+  }
+#endif
+#else
+    // Assume UP for now for VMX
+    bx_mem.init_memory(megabytes * 1024 * 1024);
+    bx_cpu.init(&bx_mem);
+#endif // BX_USE_VMX
+
+#if BX_DEBUGGER == 0
+  DEV_init_devices();
+  DEV_reset_devices(BX_RESET_HARDWARE);
+  bx_gui->init_signal_handlers ();
+  bx_pc_system.start_timers();
+#endif
+  BX_DEBUG(("bx_init_hardware is setting signal handlers"));
+// if not using debugger, then we can take control of SIGINT.
+#if !BX_DEBUGGER
+  signal(SIGINT, bx_signal_handler);
+#endif
+
+#if BX_SHOW_IPS
+#ifndef __MINGW32__
+  signal(SIGALRM, bx_signal_handler);
+#endif
+  alarm( 1 );
+#endif
+
+  return(0);
+}
+
+
+
+  void
+bx_init_bx_dbg (void)
+{
+  bx_dbg.floppy = 0;
+  bx_dbg.keyboard = 0;
+  bx_dbg.video = 0;
+  bx_dbg.disk = 0;
+  bx_dbg.pit = 0;
+  bx_dbg.pic = 0;
+  bx_dbg.bios = 0;
+  bx_dbg.cmos = 0;
+  bx_dbg.a20 = 0;
+  bx_dbg.interrupts = 0;
+  bx_dbg.exceptions = 0;
+  bx_dbg.unsupported = 0;
+  bx_dbg.temp = 0;
+  bx_dbg.reset = 0;
+  bx_dbg.mouse = 0;
+  bx_dbg.io = 0;
+  bx_dbg.debugger = 0;
+  bx_dbg.xms = 0;
+  bx_dbg.v8086 = 0;
+  bx_dbg.paging = 0;
+  bx_dbg.creg = 0;
+  bx_dbg.dreg = 0;
+  bx_dbg.dma = 0;
+  bx_dbg.unsupported_io = 0;
+  bx_dbg.record_io = 0;
+  bx_dbg.serial = 0;
+  bx_dbg.cdrom = 0;
+#ifdef MAGIC_BREAKPOINT
+  bx_dbg.magic_break_enabled = 0;
+#endif
+
+}
+
+
+int
+bx_atexit(void)
+{
+  static bx_bool been_here = 0;
+  if (been_here) return 1;   // protect from reentry
+  been_here = 1;
+
+  // in case we ended up in simulation mode, change back to config mode
+  // so that the user can see any messages left behind on the console.
+  SIM->set_display_mode (DISP_MODE_CONFIG);
+
+#if BX_PROVIDE_DEVICE_MODELS==1
+  bx_pc_system.exit();
+#endif
+
+#if BX_DEBUGGER == 0
+  if (SIM && SIM->get_init_done ()) {
+    for (int cpu=0; cpu<BX_SMP_PROCESSORS; cpu++)
+      if (BX_CPU(cpu)) BX_CPU(cpu)->atexit();
+  }
+#endif
+
+#if BX_PCI_SUPPORT
+  if (bx_options.Oi440FXSupport->get ()) {
+    bx_devices.pluginPciBridge->print_i440fx_state();
+    }
+#endif
+
+  // restore signal handling to defaults
+#if !BX_DEBUGGER
+  BX_INFO (("restoring default signal behavior"));
+  signal(SIGINT, SIG_DFL);
+#endif
+
+#if BX_SHOW_IPS
+#ifndef __MINGW32__
+  signal(SIGALRM, SIG_DFL);
+#endif
+#endif
+        return 0;
+}
+
+#if BX_PROVIDE_MAIN
+
+char *
+bx_find_bochsrc ()
+{
+  FILE *fd = NULL;
+  char rcfile[512];
+  Bit32u retry = 0, found = 0;
+  // try several possibilities for the bochsrc before giving up
+  while (!found) {
+    rcfile[0] = 0;
+    switch (retry++) {
+    case 0: strcpy (rcfile, ".bochsrc"); break;
+    case 1: strcpy (rcfile, "bochsrc"); break;
+    case 2: strcpy (rcfile, "bochsrc.txt"); break;
+#ifdef WIN32
+    case 3: strcpy (rcfile, "bochsrc.bxrc"); break;
+#elif !BX_WITH_MACOS
+      // only try this on unix
+    case 3:
+      {
+      char *ptr = getenv("HOME");
+      if (ptr) snprintf (rcfile, sizeof(rcfile), "%s/.bochsrc", ptr);
+      }
+      break;
+     case 4: strcpy (rcfile, "/etc/bochsrc"); break;
+#endif
+    default:
+      return NULL;
+    }
+    if (rcfile[0]) {
+      BX_DEBUG (("looking for configuration in %s", rcfile));
+      fd = fopen(rcfile, "r");
+      if (fd) found = 1;
+    }
+  }
+  assert (fd != NULL && rcfile[0] != 0);
+  fclose (fd);
+  return strdup (rcfile);
+}
+
+  static int
+parse_bochsrc(char *rcfile)
+{
+  FILE *fd = NULL;
+  char *ret;
+  char line[512];
+
+  // try several possibilities for the bochsrc before giving up
+
+  bochsrc_include_count++;
+
+  fd = fopen (rcfile, "r");
+  if (fd == NULL) return -1;
+
+  int retval = 0;
+  do {
+    ret = fgets(line, sizeof(line)-1, fd);
+    line[sizeof(line) - 1] = '\0';
+    int len = strlen(line);
+    if (len>0)
+      line[len-1] = '\0';
+    if ((ret != NULL) && strlen(line)) {
+      if (parse_line_unformatted(rcfile, line) < 0) {
+        retval = -1;
+        break;  // quit parsing after first error
+        }
+      }
+    } while (!feof(fd));
+  fclose(fd);
+  bochsrc_include_count--;
+  return retval;
+}
+
+  static Bit32s
+parse_line_unformatted(char *context, char *line)
+{
+#define MAX_PARAMS_LEN 40
+  char *ptr;
+  unsigned i, string_i;
+  char string[512];
+  char *params[MAX_PARAMS_LEN];
+  int num_params;
+  bx_bool inquotes = 0;
+  bx_bool comment = 0;
+
+  memset(params, 0, sizeof(params));
+  if (line == NULL) return 0;
+
+  // if passed nothing but whitespace, just return
+  for (i=0; i<strlen(line); i++) {
+    if (!isspace(line[i])) break;
+    }
+  if (i>=strlen(line))
+    return 0;
+
+  num_params = 0;
+
+  if (!strncmp(line, "#include", 8))
+    ptr = strtok(line, " ");
+  else
+    ptr = strtok(line, ":");
+  while ((ptr) && (!comment)) {
+    string_i = 0;
+    for (i=0; i<strlen(ptr); i++) {
+      if (ptr[i] == '"')
+        inquotes = !inquotes;
+      else if ((ptr[i] == '#') && (strncmp(line+i, "#include", 8)) && !inquotes) {
+        comment = 1;
+        break;
+      } else {
+#if BX_HAVE_GETENV
+        // substitute environment variables.
+        if (ptr[i] == '$') {
+          char varname[512];
+          char *pv = varname;
+          char *value;
+          *pv = 0;
+          i++;
+          while (isalpha(ptr[i]) || ptr[i]=='_') {
+            *pv = ptr[i]; pv++; i++;
+          }
+          *pv = 0;
+          if (strlen(varname)<1 || !(value = getenv(varname))) {
+              BX_PANIC (("could not look up environment variable '%s'", varname));
+          } else {
+            // append value to the string
+            for (pv=value; *pv; pv++)
+                string[string_i++] = *pv;
+          }
+        }
+#endif
+        if (!isspace(ptr[i]) || inquotes) {
+          string[string_i++] = ptr[i];
+        }
+      }
+    }
+    string[string_i] = '\0';
+    if (string_i == 0) break;
+    if ( params[num_params] != NULL )
+    {
+        free(params[num_params]);
+        params[num_params] = NULL;
+    }
+    if ( num_params < MAX_PARAMS_LEN )
+    {
+    params[num_params++] = strdup (string);
+    ptr = strtok(NULL, ",");
+  }
+    else
+    {
+        BX_PANIC (("too many parameters, max is %d\n", MAX_PARAMS_LEN));
+    }
+  }
+  Bit32s retval = parse_line_formatted(context, num_params, &params[0]);
+  for (i=0; i < MAX_PARAMS_LEN; i++)
+  {
+    if ( params[i] != NULL )
+    {
+        free(params[i]);
+        params[i] = NULL;
+    }
+  }
+  return retval;
+}
+
+// These macros are called for all parse errors, so that we can easily
+// change the behavior of all occurrences.
+#define PARSE_ERR(x)  \
+  do { BX_PANIC(x); return -1; } while (0)
+#define PARSE_WARN(x)  \
+  BX_ERROR(x)
+
+  static Bit32s
+parse_line_formatted(char *context, int num_params, char *params[])
+{
+  int i;
+
+  if (num_params < 1) return 0;
+  if (num_params < 2) {
+    PARSE_ERR(("%s: a bochsrc option needs at least one parameter", context));
+  }
+
+  if (!strcmp(params[0], "#include")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: ignoring malformed #include directive.", context));
+      }
+    if (!strcmp(params[1], context)) {
+      PARSE_ERR(("%s: cannot include this file again.", context));
+      }
+    if (bochsrc_include_count == 2) {
+      PARSE_ERR(("%s: include directive in an included file not supported yet.", context));
+      }
+    bx_read_configuration(params[1]);
+    }
+  else if (!strcmp(params[0], "floppya")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "2_88=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_2_88);
+        }
+      else if (!strncmp(params[i], "1_44=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_1_44);
+        }
+      else if (!strncmp(params[i], "1_2=", 4)) {
+        bx_options.floppya.Opath->set (&params[i][4]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_1_2);
+        }
+      else if (!strncmp(params[i], "720k=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_720K);
+        }
+      else if (!strncmp(params[i], "360k=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_360K);
+        }
+      // use CMOS reserved types?
+      else if (!strncmp(params[i], "160k=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_160K);
+        }
+      else if (!strncmp(params[i], "180k=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_180K);
+        }
+      else if (!strncmp(params[i], "320k=", 5)) {
+        bx_options.floppya.Opath->set (&params[i][5]);
+        bx_options.floppya.Otype->set (BX_FLOPPY_320K);
+        }
+      else if (!strncmp(params[i], "status=ejected", 14)) {
+        bx_options.floppya.Ostatus->set (BX_EJECTED);
+        }
+      else if (!strncmp(params[i], "status=inserted", 15)) {
+        bx_options.floppya.Ostatus->set (BX_INSERTED);
+        }
+      else {
+        PARSE_ERR(("%s: floppya attribute '%s' not understood.", context,
+          params[i]));
+        }
+      }
+    }
+   else if (!strcmp(params[0], "gdbstub_port"))
+     {
+       if (num_params != 2)
+         {
+            fprintf(stderr, ".bochsrc: gdbstub_port directive: wrong # args.\n");
+            exit(1);
+         }
+       bx_options.gdbstub.port = atoi(params[1]);
+     }
+   else if (!strcmp(params[0], "gdbstub_text_base"))
+     {
+       if (num_params != 2)
+         {
+            fprintf(stderr, ".bochsrc: gdbstub_text_base directive: wrong # args.\n");
+            exit(1);
+         }
+       bx_options.gdbstub.text_base = atoi(params[1]);
+     }
+   else if (!strcmp(params[0], "gdbstub_data_base"))
+     {
+       if (num_params != 2)
+         {
+            fprintf(stderr, ".bochsrc: gdbstub_data_base directive: wrong # args.\n");
+            exit(1);
+         }
+       bx_options.gdbstub.data_base = atoi(params[1]);
+     }
+   else if (!strcmp(params[0], "gdbstub_bss_base"))
+     {
+       if (num_params != 2)
+         {
+            fprintf(stderr, ".bochsrc: gdbstub_bss_base directive: wrong # args.\n");
+            exit(1);
+         }
+       bx_options.gdbstub.bss_base = atoi(params[1]);
+     }
+
+  else if (!strcmp(params[0], "floppyb")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "2_88=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_2_88);
+        }
+      else if (!strncmp(params[i], "1_44=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_1_44);
+        }
+      else if (!strncmp(params[i], "1_2=", 4)) {
+        bx_options.floppyb.Opath->set (&params[i][4]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_1_2);
+        }
+      else if (!strncmp(params[i], "720k=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_720K);
+        }
+      else if (!strncmp(params[i], "360k=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_360K);
+        }
+      // use CMOS reserved types?
+      else if (!strncmp(params[i], "160k=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_160K);
+        }
+      else if (!strncmp(params[i], "180k=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_180K);
+        }
+      else if (!strncmp(params[i], "320k=", 5)) {
+        bx_options.floppyb.Opath->set (&params[i][5]);
+        bx_options.floppyb.Otype->set (BX_FLOPPY_320K);
+        }
+      else if (!strncmp(params[i], "status=ejected", 14)) {
+        bx_options.floppyb.Ostatus->set (BX_EJECTED);
+        }
+      else if (!strncmp(params[i], "status=inserted", 15)) {
+        bx_options.floppyb.Ostatus->set (BX_INSERTED);
+        }
+      else {
+        PARSE_ERR(("%s: floppyb attribute '%s' not understood.", context,
+          params[i]));
+        }
+      }
+    }
+
+  else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) == 4)) {
+    Bit8u channel = params[0][3];
+
+    if ((channel < '0') || (channel > '9')) {
+      PARSE_ERR(("%s: ataX directive malformed.", context));
+      }
+    channel-='0';
+    if (channel >= BX_MAX_ATA_CHANNEL) {
+      PARSE_ERR(("%s: ataX directive malformed.", context));
+      }
+
+    if ((num_params < 2) || (num_params > 5)) {
+      PARSE_ERR(("%s: ataX directive malformed.", context));
+      }
+
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: ataX directive malformed.", context));
+      }
+    else {
+      bx_options.ata[channel].Opresent->set (atol(&params[1][8]));
+      }
+
+    if (num_params > 2) {
+      if (strncmp(params[2], "ioaddr1=", 8)) {
+        PARSE_ERR(("%s: ataX directive malformed.", context));
+        }
+      else {
+        if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+          bx_options.ata[channel].Oioaddr1->set (strtoul (&params[2][8], NULL, 16));
+        else
+          bx_options.ata[channel].Oioaddr1->set (strtoul (&params[2][8], NULL, 10));
+        }
+      }
+
+    if (num_params > 3) {
+      if (strncmp(params[3], "ioaddr2=", 8)) {
+        PARSE_ERR(("%s: ataX directive malformed.", context));
+        }
+      else {
+        if ( (params[3][8] == '0') && (params[3][9] == 'x') )
+          bx_options.ata[channel].Oioaddr2->set (strtoul (&params[3][8], NULL, 16));
+        else
+          bx_options.ata[channel].Oioaddr2->set (strtoul (&params[3][8], NULL, 10));
+        }
+      }
+
+    if (num_params > 4) {
+      if (strncmp(params[4], "irq=", 4)) {
+        PARSE_ERR(("%s: ataX directive malformed.", context));
+        }
+      else {
+        bx_options.ata[channel].Oirq->set (atol(&params[4][4]));
+        }
+      }
+    }
+
+  // ataX-master, ataX-slave
+  else if ((!strncmp(params[0], "ata", 3)) && (strlen(params[0]) > 4)) {
+    Bit8u channel = params[0][3], slave = 0;
+
+    if ((channel < '0') || (channel > '9')) {
+      PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+      }
+    channel-='0';
+    if (channel >= BX_MAX_ATA_CHANNEL) {
+      PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+      }
+
+    if ((strcmp(&params[0][4], "-slave")) &&
+        (strcmp(&params[0][4], "-master"))) {
+      PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+      }
+
+    if (!strcmp(&params[0][4], "-slave")) {
+      slave = 1;
+      }
+
+    // This was originally meant to warn users about both diskc
+    // and ata0-master defined, but it also prevent users to
+    // override settings on the command line 
+    // (see [ 661010 ] cannot override ata-settings from cmdline)
+    // if (bx_options.atadevice[channel][slave].Opresent->get()) {
+    //   BX_INFO(("%s: %s device of ata channel %d already defined.", context, slave?"slave":"master",channel));
+    //   }
+
+    for (i=1; i<num_params; i++) {
+      if (!strcmp(params[i], "type=disk")) {
+        bx_options.atadevice[channel][slave].Otype->set (BX_ATA_DEVICE_DISK);
+        }
+      else if (!strcmp(params[i], "type=cdrom")) {
+        bx_options.atadevice[channel][slave].Otype->set (BX_ATA_DEVICE_CDROM);
+        }
+      else if (!strcmp(params[i], "mode=flat")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_FLAT);
+        }
+      else if (!strcmp(params[i], "mode=concat")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_CONCAT);
+        }
+      else if (!strcmp(params[i], "mode=external")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_EXTDISKSIM);
+        }
+      else if (!strcmp(params[i], "mode=dll")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_DLL_HD);
+        }
+      else if (!strcmp(params[i], "mode=sparse")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_SPARSE);
+        }
+      else if (!strcmp(params[i], "mode=vmware3")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_VMWARE3);
+        }
+//      else if (!strcmp(params[i], "mode=split")) {
+//        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_SPLIT);
+//        }
+      else if (!strcmp(params[i], "mode=undoable")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_UNDOABLE);
+        }
+      else if (!strcmp(params[i], "mode=growing")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_GROWING);
+        }
+      else if (!strcmp(params[i], "mode=volatile")) {
+        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_VOLATILE);
+        }
+//      else if (!strcmp(params[i], "mode=z-undoable")) {
+//        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_Z_UNDOABLE);
+//        }
+//      else if (!strcmp(params[i], "mode=z-volatile")) {
+//        bx_options.atadevice[channel][slave].Omode->set (BX_ATA_MODE_Z_VOLATILE);
+//        }
+      else if (!strncmp(params[i], "path=", 5)) {
+        bx_options.atadevice[channel][slave].Opath->set (&params[i][5]);
+        }
+      else if (!strncmp(params[i], "cylinders=", 10)) {
+        bx_options.atadevice[channel][slave].Ocylinders->set (atol(&params[i][10]));
+        }
+      else if (!strncmp(params[i], "heads=", 6)) {
+        bx_options.atadevice[channel][slave].Oheads->set (atol(&params[i][6]));
+        }
+      else if (!strncmp(params[i], "spt=", 4)) {
+        bx_options.atadevice[channel][slave].Ospt->set (atol(&params[i][4]));
+        }
+      else if (!strncmp(params[i], "model=", 6)) {
+        bx_options.atadevice[channel][slave].Omodel->set(&params[i][6]);
+        }
+      else if (!strcmp(params[i], "biosdetect=none")) {
+        bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_NONE);
+        }
+      else if (!strcmp(params[i], "biosdetect=cmos")) {
+        bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_CMOS);
+        }
+      else if (!strcmp(params[i], "biosdetect=auto")) {
+        bx_options.atadevice[channel][slave].Obiosdetect->set(BX_ATA_BIOSDETECT_AUTO);
+        }
+      else if (!strcmp(params[i], "translation=none")) {
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_NONE);
+        }
+      else if (!strcmp(params[i], "translation=lba")) {
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LBA);
+        }
+      else if (!strcmp(params[i], "translation=large")) { 
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LARGE);
+        }
+      else if (!strcmp(params[i], "translation=echs")) { // synonym of large
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_LARGE);
+        }
+      else if (!strcmp(params[i], "translation=rechs")) {
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_RECHS);
+        }
+      else if (!strcmp(params[i], "translation=auto")) {
+        bx_options.atadevice[channel][slave].Otranslation->set(BX_ATA_TRANSLATION_AUTO);
+        }
+      else if (!strcmp(params[i], "status=ejected")) {
+        bx_options.atadevice[channel][slave].Ostatus->set(BX_EJECTED);
+        }
+      else if (!strcmp(params[i], "status=inserted")) {
+        bx_options.atadevice[channel][slave].Ostatus->set(BX_INSERTED);
+        }
+      else if (!strncmp(params[i], "journal=", 8)) {
+        bx_options.atadevice[channel][slave].Ojournal->set(&params[i][8]);
+        }
+      else {
+        PARSE_ERR(("%s: ataX-master/slave directive malformed.", context));
+        }
+      }
+
+    // Enables the ata device
+    bx_options.atadevice[channel][slave].Opresent->set(1);
+
+    // if enabled, check if device ok
+    if (bx_options.atadevice[channel][slave].Opresent->get() == 1) {
+      if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_DISK) {
+        if (strlen(bx_options.atadevice[channel][slave].Opath->getptr()) ==0)
+          PARSE_WARN(("%s: ataX-master/slave has empty path", context));
+        if ((bx_options.atadevice[channel][slave].Ocylinders->get() == 0) ||
+            (bx_options.atadevice[channel][slave].Oheads->get() ==0 ) ||
+            (bx_options.atadevice[channel][slave].Ospt->get() == 0)) {
+          PARSE_WARN(("%s: ataX-master/slave cannot have zero cylinders, heads, or sectors/track", context));
+          }
+        }
+      else if (bx_options.atadevice[channel][slave].Otype->get() == BX_ATA_DEVICE_CDROM) {
+        if (strlen(bx_options.atadevice[channel][slave].Opath->getptr()) == 0) {
+          PARSE_WARN(("%s: ataX-master/slave has empty path", context));
+          }
+        }
+      else {
+        PARSE_WARN(("%s: ataX-master/slave: type should be specified", context));
+        }
+      }
+    }
+
+  // Legacy disk options emulation
+  else if (!strcmp(params[0], "diskc")) { // DEPRECATED
+    BX_INFO(("WARNING: diskc directive is deprecated, use ata0-master: instead"));
+    if (bx_options.atadevice[0][0].Opresent->get()) {
+      PARSE_ERR(("%s: master device of ata channel 0 already defined.", context));
+      }
+    if (num_params != 5) {
+      PARSE_ERR(("%s: diskc directive malformed.", context));
+      }
+    if (strncmp(params[1], "file=", 5) ||
+        strncmp(params[2], "cyl=", 4) ||
+        strncmp(params[3], "heads=", 6) ||
+        strncmp(params[4], "spt=", 4)) {
+      PARSE_ERR(("%s: diskc directive malformed.", context));
+      }
+    bx_options.ata[0].Opresent->set(1);
+    bx_options.atadevice[0][0].Otype->set (BX_ATA_DEVICE_DISK);
+    bx_options.atadevice[0][0].Opath->set (&params[1][5]);
+    bx_options.atadevice[0][0].Ocylinders->set (atol(&params[2][4]));
+    bx_options.atadevice[0][0].Oheads->set     (atol(&params[3][6]));
+    bx_options.atadevice[0][0].Ospt->set       (atol(&params[4][4]));
+    bx_options.atadevice[0][0].Opresent->set (1);
+    }
+  else if (!strcmp(params[0], "diskd")) { // DEPRECATED
+    BX_INFO(("WARNING: diskd directive is deprecated, use ata0-slave: instead"));
+    if (bx_options.atadevice[0][1].Opresent->get()) {
+      PARSE_ERR(("%s: slave device of ata channel 0 already defined.", context));
+      }
+    if (num_params != 5) {
+      PARSE_ERR(("%s: diskd directive malformed.", context));
+      }
+    if (strncmp(params[1], "file=", 5) ||
+        strncmp(params[2], "cyl=", 4) ||
+        strncmp(params[3], "heads=", 6) ||
+        strncmp(params[4], "spt=", 4)) {
+      PARSE_ERR(("%s: diskd directive malformed.", context));
+      }
+    bx_options.ata[0].Opresent->set(1);
+    bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_DISK);
+    bx_options.atadevice[0][1].Opath->set (&params[1][5]);
+    bx_options.atadevice[0][1].Ocylinders->set (atol( &params[2][4]));
+    bx_options.atadevice[0][1].Oheads->set     (atol( &params[3][6]));
+    bx_options.atadevice[0][1].Ospt->set       (atol( &params[4][4]));
+    bx_options.atadevice[0][1].Opresent->set (1);
+    }
+  else if (!strcmp(params[0], "cdromd")) { // DEPRECATED
+    BX_INFO(("WARNING: cdromd directive is deprecated, use ata0-slave: instead"));
+    if (bx_options.atadevice[0][1].Opresent->get()) {
+      PARSE_ERR(("%s: slave device of ata channel 0 already defined.", context));
+      }
+    if (num_params != 3) {
+      PARSE_ERR(("%s: cdromd directive malformed.", context));
+      }
+    if (strncmp(params[1], "dev=", 4) || strncmp(params[2], "status=", 7)) {
+      PARSE_ERR(("%s: cdromd directive malformed.", context));
+      }
+    bx_options.ata[0].Opresent->set(1);
+    bx_options.atadevice[0][1].Otype->set (BX_ATA_DEVICE_CDROM);
+    bx_options.atadevice[0][1].Opath->set (&params[1][4]);
+    if (!strcmp(params[2], "status=inserted"))
+      bx_options.atadevice[0][1].Ostatus->set (BX_INSERTED);
+    else if (!strcmp(params[2], "status=ejected"))
+      bx_options.atadevice[0][1].Ostatus->set (BX_EJECTED);
+    else {
+      PARSE_ERR(("%s: cdromd directive malformed.", context));
+      }
+    bx_options.atadevice[0][1].Opresent->set (1);
+    }
+
+  else if (!strcmp(params[0], "boot")) {
+    if (!strcmp(params[1], "a")) {
+      bx_options.Obootdrive->set (BX_BOOT_FLOPPYA);
+    } else if (!strcmp(params[1], "floppy")) {
+      bx_options.Obootdrive->set (BX_BOOT_FLOPPYA);
+    } else if (!strcmp(params[1], "c")) {
+      bx_options.Obootdrive->set (BX_BOOT_DISKC);
+    } else if (!strcmp(params[1], "disk")) {
+      bx_options.Obootdrive->set (BX_BOOT_DISKC);
+    } else if (!strcmp(params[1], "cdrom")) {
+      bx_options.Obootdrive->set (BX_BOOT_CDROM);
+    } else {
+      PARSE_ERR(("%s: boot directive with unknown boot device '%s'.  use 'floppy', 'disk' or 'cdrom'.", context, params[1]));
+      }
+    }
+
+  else if (!strcmp(params[0], "com1")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.com[0].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "dev=", 4)) {
+        bx_options.com[0].Odev->set (&params[i][4]);
+        bx_options.com[0].Oenabled->set (1);
+        }
+      else {
+        PARSE_ERR(("%s: unknown parameter for com1 ignored.", context));
+        }
+      }
+    }
+#if 0
+  else if (!strcmp(params[0], "com2")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.com[1].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "dev=", 4)) {
+        bx_options.com[1].Odev->set (&params[i][4]);
+        bx_options.com[1].Oenabled->set (1);
+        }
+      else {
+        PARSE_ERR(("%s: unknown parameter for com2 ignored.", context));
+        }
+      }
+    }
+  else if (!strcmp(params[0], "com3")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.com[2].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "dev=", 4)) {
+        bx_options.com[2].Odev->set (&params[i][4]);
+        bx_options.com[2].Oenabled->set (1);
+        }
+      else {
+        PARSE_ERR(("%s: unknown parameter for com3 ignored.", context));
+        }
+      }
+    }
+  else if (!strcmp(params[0], "com4")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.com[3].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "dev=", 4)) {
+        bx_options.com[3].Odev->set (&params[i][4]);
+        bx_options.com[3].Oenabled->set (1);
+        }
+      else {
+        PARSE_ERR(("%s: unknown parameter for com4 ignored.", context));
+        }
+      }
+    }
+#endif
+  else if (!strcmp(params[0], "usb1")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.usb[0].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "ioaddr=", 7)) {
+        if ( (params[i][7] == '0') && (params[i][8] == 'x') )
+          bx_options.usb[0].Oioaddr->set (strtoul (&params[i][7], NULL, 16));
+        else
+          bx_options.usb[0].Oioaddr->set (strtoul (&params[i][7], NULL, 10));
+        bx_options.usb[0].Oenabled->set (1);
+        }
+      else if (!strncmp(params[i], "irq=", 4)) {
+        bx_options.usb[0].Oirq->set (atol(&params[i][4]));
+        }
+      else {
+        PARSE_ERR(("%s: unknown parameter for usb1 ignored.", context));
+        }
+      }
+    }
+  else if (!strcmp(params[0], "floppy_bootsig_check")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+      }
+    if (strncmp(params[1], "disabled=", 9)) {
+      PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+      }
+    if (params[1][9] == '0')
+      bx_options.OfloppySigCheck->set (0);
+    else if (params[1][9] == '1')
+      bx_options.OfloppySigCheck->set (1);
+    else {
+      PARSE_ERR(("%s: floppy_bootsig_check directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "log")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: log directive has wrong # args.", context));
+      }
+    bx_options.log.Ofilename->set (params[1]);
+    }
+  else if (!strcmp(params[0], "logprefix")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: logprefix directive has wrong # args.", context));
+      }
+    bx_options.log.Oprefix->set (params[1]);
+    }
+  else if (!strcmp(params[0], "debugger_log")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: debugger_log directive has wrong # args.", context));
+      }
+    bx_options.log.Odebugger_filename->set (params[1]);
+    }
+  else if (!strcmp(params[0], "panic")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: panic directive malformed.", context));
+      }
+    if (strncmp(params[1], "action=", 7)) {
+      PARSE_ERR(("%s: panic directive malformed.", context));
+      }
+    char *action = 7 + params[1];
+    if (!strcmp(action, "fatal"))
+      SIM->set_default_log_action (LOGLEV_PANIC, ACT_FATAL);
+    else if (!strcmp (action, "report"))
+      SIM->set_default_log_action (LOGLEV_PANIC, ACT_REPORT);
+    else if (!strcmp (action, "ignore"))
+      SIM->set_default_log_action (LOGLEV_PANIC, ACT_IGNORE);
+    else if (!strcmp (action, "ask"))
+      SIM->set_default_log_action (LOGLEV_PANIC, ACT_ASK);
+    else {
+      PARSE_ERR(("%s: panic directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "pass")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: pass directive malformed.", context));
+      }
+    if (strncmp(params[1], "action=", 7)) {
+      PARSE_ERR(("%s: pass directive malformed.", context));
+      }
+    char *action = 7 + params[1];
+    if (!strcmp(action, "fatal"))
+      SIM->set_default_log_action (LOGLEV_PASS, ACT_FATAL);
+    else if (!strcmp (action, "report"))
+      SIM->set_default_log_action (LOGLEV_PASS, ACT_REPORT);
+    else if (!strcmp (action, "ignore"))
+      SIM->set_default_log_action (LOGLEV_PASS, ACT_IGNORE);
+    else if (!strcmp (action, "ask"))
+      SIM->set_default_log_action (LOGLEV_PASS, ACT_ASK);
+    else {
+      PARSE_ERR(("%s: pass directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "error")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: error directive malformed.", context));
+      }
+    if (strncmp(params[1], "action=", 7)) {
+      PARSE_ERR(("%s: error directive malformed.", context));
+      }
+    char *action = 7 + params[1];
+    if (!strcmp(action, "fatal"))
+      SIM->set_default_log_action (LOGLEV_ERROR, ACT_FATAL);
+    else if (!strcmp (action, "report"))
+      SIM->set_default_log_action (LOGLEV_ERROR, ACT_REPORT);
+    else if (!strcmp (action, "ignore"))
+      SIM->set_default_log_action (LOGLEV_ERROR, ACT_IGNORE);
+    else if (!strcmp (action, "ask"))
+      SIM->set_default_log_action (LOGLEV_ERROR, ACT_ASK);
+    else {
+      PARSE_ERR(("%s: error directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "info")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: info directive malformed.", context));
+      }
+    if (strncmp(params[1], "action=", 7)) {
+      PARSE_ERR(("%s: info directive malformed.", context));
+      }
+    char *action = 7 + params[1];
+    if (!strcmp(action, "fatal"))
+      SIM->set_default_log_action (LOGLEV_INFO, ACT_FATAL);
+    else if (!strcmp (action, "report"))
+      SIM->set_default_log_action (LOGLEV_INFO, ACT_REPORT);
+    else if (!strcmp (action, "ignore"))
+      SIM->set_default_log_action (LOGLEV_INFO, ACT_IGNORE);
+    else if (!strcmp (action, "ask"))
+      SIM->set_default_log_action (LOGLEV_INFO, ACT_ASK);
+    else {
+      PARSE_ERR(("%s: info directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "debug")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: debug directive malformed.", context));
+      }
+    if (strncmp(params[1], "action=", 7)) {
+      PARSE_ERR(("%s: debug directive malformed.", context));
+      }
+    char *action = 7 + params[1];
+    if (!strcmp(action, "fatal"))
+      SIM->set_default_log_action (LOGLEV_DEBUG, ACT_FATAL);
+    else if (!strcmp (action, "report"))
+      SIM->set_default_log_action (LOGLEV_DEBUG, ACT_REPORT);
+    else if (!strcmp (action, "ignore"))
+      SIM->set_default_log_action (LOGLEV_DEBUG, ACT_IGNORE);
+    else if (!strcmp (action, "ask"))
+      SIM->set_default_log_action (LOGLEV_DEBUG, ACT_ASK);
+    else {
+      PARSE_ERR(("%s: debug directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "romimage")) {
+    if (num_params != 3) {
+      PARSE_ERR(("%s: romimage directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "file=", 5)) {
+      PARSE_ERR(("%s: romimage directive malformed.", context));
+      }
+    if (strncmp(params[2], "address=", 8)) {
+      PARSE_ERR(("%s: romimage directive malformed.", context));
+      }
+    bx_options.rom.Opath->set (&params[1][5]);
+    if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+      bx_options.rom.Oaddress->set (strtoul (&params[2][8], NULL, 16));
+    else
+      bx_options.rom.Oaddress->set (strtoul (&params[2][8], NULL, 10));
+    }
+  else if (!strcmp(params[0], "optromimage1")) {
+    if (num_params != 3) {
+      PARSE_ERR(("%s: optromimage1 directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "file=", 5)) {
+      PARSE_ERR(("%s: optromimage1 directive malformed.", context));
+      }
+    if (strncmp(params[2], "address=", 8)) {
+      PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+      }
+    bx_options.optrom[0].Opath->set (&params[1][5]);
+    if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+      bx_options.optrom[0].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+    else
+      bx_options.optrom[0].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+    }
+  else if (!strcmp(params[0], "optromimage2")) {
+    if (num_params != 3) {
+      PARSE_ERR(("%s: optromimage2 directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "file=", 5)) {
+      PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+      }
+    if (strncmp(params[2], "address=", 8)) {
+      PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+      }
+    bx_options.optrom[1].Opath->set (&params[1][5]);
+    if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+      bx_options.optrom[1].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+    else
+      bx_options.optrom[1].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+    }
+  else if (!strcmp(params[0], "optromimage3")) {
+    if (num_params != 3) {
+      PARSE_ERR(("%s: optromimage3 directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "file=", 5)) {
+      PARSE_ERR(("%s: optromimage3 directive malformed.", context));
+      }
+    if (strncmp(params[2], "address=", 8)) {
+      PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+      }
+    bx_options.optrom[2].Opath->set (&params[1][5]);
+    if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+      bx_options.optrom[2].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+    else
+      bx_options.optrom[2].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+    }
+  else if (!strcmp(params[0], "optromimage4")) {
+    if (num_params != 3) {
+      PARSE_ERR(("%s: optromimage4 directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "file=", 5)) {
+      PARSE_ERR(("%s: optromimage4 directive malformed.", context));
+      }
+    if (strncmp(params[2], "address=", 8)) {
+      PARSE_ERR(("%s: optromimage2 directive malformed.", context));
+      }
+    bx_options.optrom[3].Opath->set (&params[1][5]);
+    if ( (params[2][8] == '0') && (params[2][9] == 'x') )
+      bx_options.optrom[3].Oaddress->set (strtoul (&params[2][8], NULL, 16));
+    else
+      bx_options.optrom[3].Oaddress->set (strtoul (&params[2][8], NULL, 10));
+    }
+  else if (!strcmp(params[0], "vgaromimage")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: vgaromimage directive: wrong # args.", context));
+      }
+    bx_options.vgarom.Opath->set (params[1]);
+    }
+  else if (!strcmp(params[0], "vga_update_interval")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: vga_update_interval directive: wrong # args.", context));
+      }
+    bx_options.Ovga_update_interval->set (atol(params[1]));
+    if (bx_options.Ovga_update_interval->get () < 50000) {
+      BX_INFO(("%s: vga_update_interval seems awfully small!", context));
+      }
+    }
+  else if (!strcmp(params[0], "keyboard_serial_delay")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: keyboard_serial_delay directive: wrong # args.", context));
+      }
+    bx_options.Okeyboard_serial_delay->set (atol(params[1]));
+    if (bx_options.Okeyboard_serial_delay->get () < 5) {
+      PARSE_ERR (("%s: keyboard_serial_delay not big enough!", context));
+      }
+    }
+  else if (!strcmp(params[0], "keyboard_paste_delay")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: keyboard_paste_delay directive: wrong # args.", context));
+      }
+    bx_options.Okeyboard_paste_delay->set (atol(params[1]));
+    if (bx_options.Okeyboard_paste_delay->get () < 1000) {
+      PARSE_ERR (("%s: keyboard_paste_delay not big enough!", context));
+      }
+    }
+  else if (!strcmp(params[0], "megs")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: megs directive: wrong # args.", context));
+      }
+    bx_options.memory.Osize->set (atol(params[1]));
+    }
+  else if (!strcmp(params[0], "floppy_command_delay")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: floppy_command_delay directive: wrong # args.", context));
+      }
+    bx_options.Ofloppy_command_delay->set (atol(params[1]));
+    if (bx_options.Ofloppy_command_delay->get () < 100) {
+      PARSE_ERR(("%s: floppy_command_delay not big enough!", context));
+      }
+    }
+  else if (!strcmp(params[0], "ips")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: ips directive: wrong # args.", context));
+      }
+    bx_options.Oips->set (atol(params[1]));
+    if (bx_options.Oips->get () < BX_MIN_IPS) {
+      BX_ERROR(("%s: WARNING: ips is AWFULLY low!", context));
+      }
+    }
+  else if (!strcmp(params[0], "pit")) { // Deprecated
+    if (num_params != 2) {
+      PARSE_ERR(("%s: pit directive: wrong # args.", context));
+      }
+    BX_INFO(("WARNING: pit directive is deprecated, use clock: instead"));
+    if (!strncmp(params[1], "realtime=", 9)) {
+      switch (params[1][9]) {
+        case '0': 
+          BX_INFO(("WARNING: not disabling realtime pit"));
+          break;
+        case '1': bx_options.clock.Osync->set (BX_CLOCK_SYNC_REALTIME); break;
+        default: PARSE_ERR(("%s: pit expected realtime=[0|1] arg", context));
+        }
+      }
+    else PARSE_ERR(("%s: pit expected realtime=[0|1] arg", context));
+    }
+  else if (!strcmp(params[0], "max_ips")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: max_ips directive: wrong # args.", context));
+      }
+    BX_INFO(("WARNING: max_ips not implemented"));
+    }
+  else if (!strcmp(params[0], "text_snapshot_check")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: text_snapshot_check directive: wrong # args.", context));
+      }
+    if (!strncmp(params[1], "enable", 6)) {
+      bx_options.Otext_snapshot_check->set (1);
+      }
+    else if (!strncmp(params[1], "disable", 7)) {
+      bx_options.Otext_snapshot_check->set (0);
+      }
+    else bx_options.Otext_snapshot_check->set (!!(atol(params[1])));
+    }
+  else if (!strcmp(params[0], "mouse")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: mouse directive malformed.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: mouse directive malformed.", context));
+      }
+    if (params[1][8] == '0' || params[1][8] == '1')
+      bx_options.Omouse_enabled->set (params[1][8] - '0');
+    else
+      PARSE_ERR(("%s: mouse directive malformed.", context));
+    }
+  else if (!strcmp(params[0], "private_colormap")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: private_colormap directive malformed.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: private_colormap directive malformed.", context));
+      }
+    if (params[1][8] == '0' || params[1][8] == '1')
+      bx_options.Oprivate_colormap->set (params[1][8] - '0');
+    else {
+      PARSE_ERR(("%s: private_colormap directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "fullscreen")) {
+#if BX_WITH_AMIGAOS
+    if (num_params != 2) {
+      PARSE_ERR(("%s: fullscreen directive malformed.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: fullscreen directive malformed.", context));
+      }
+    if (params[1][8] == '0' || params[1][8] == '1') {
+      bx_options.Ofullscreen->set (params[1][8] - '0');
+    } else {
+      PARSE_ERR(("%s: fullscreen directive malformed.", context));
+      }
+#endif
+    }
+  else if (!strcmp(params[0], "screenmode")) {
+#if BX_WITH_AMIGAOS
+    if (num_params != 2) {
+      PARSE_ERR(("%s: screenmode directive malformed.", context));
+      }
+    if (strncmp(params[1], "name=", 5)) {
+      PARSE_ERR(("%s: screenmode directive malformed.", context));
+      }
+    bx_options.Oscreenmode->set (strdup(&params[1][5]));
+#endif
+    }
+
+  else if (!strcmp(params[0], "sb16")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "midi=", 5)) {
+        bx_options.sb16.Omidifile->set (strdup(&params[i][5]));
+        }
+      else if (!strncmp(params[i], "midimode=", 9)) {
+        bx_options.sb16.Omidimode->set (atol(&params[i][9]));
+        }
+      else if (!strncmp(params[i], "wave=", 5)) {
+        bx_options.sb16.Owavefile->set (strdup(&params[i][5]));
+        }
+      else if (!strncmp(params[i], "wavemode=", 9)) {
+        bx_options.sb16.Owavemode->set (atol(&params[i][9]));
+        }
+      else if (!strncmp(params[i], "log=", 4)) {
+        bx_options.sb16.Ologfile->set (strdup(&params[i][4]));
+        }
+      else if (!strncmp(params[i], "loglevel=", 9)) {
+        bx_options.sb16.Ologlevel->set (atol(&params[i][9]));
+        }
+      else if (!strncmp(params[i], "dmatimer=", 9)) {
+        bx_options.sb16.Odmatimer->set (atol(&params[i][9]));
+        }
+      }
+    if (bx_options.sb16.Odmatimer->get () > 0)
+      bx_options.sb16.Opresent->set (1);
+    }
+
+  else if (!strcmp(params[0], "parport1")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.par[0].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "file=", 5)) {
+        bx_options.par[0].Ooutfile->set (strdup(&params[i][5]));
+        bx_options.par[0].Oenabled->set (1);
+        }
+      else {
+        BX_ERROR(("%s: unknown parameter for parport1 ignored.", context));
+        }
+    }
+  }
+
+#if 0
+  else if (!strcmp(params[0], "parport2")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.par[1].Oenabled->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "file=", 5)) {
+        bx_options.par[1].Ooutfile->set (strdup(&params[i][5]));
+        bx_options.par[1].Oenabled->set (1);
+        }
+      else {
+        BX_ERROR(("%s: unknown parameter for parport2 ignored.", context));
+        }
+    }
+  }
+#endif
+
+  else if (!strcmp(params[0], "i440fxsupport")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+      }
+    if (params[1][8] == '0')
+      bx_options.Oi440FXSupport->set (0);
+    else if (params[1][8] == '1')
+      bx_options.Oi440FXSupport->set (1);
+    else {
+      PARSE_ERR(("%s: i440FXSupport directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "newharddrivesupport")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+      }
+    if (params[1][8] == '0')
+      bx_options.OnewHardDriveSupport->set (0);
+    else if (params[1][8] == '1')
+      bx_options.OnewHardDriveSupport->set (1);
+    else {
+      PARSE_ERR(("%s: newharddrivesupport directive malformed.", context));
+      }
+    }
+  else if (!strcmp(params[0], "cmosimage")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: cmosimage directive: wrong # args.", context));
+      }
+    bx_options.cmos.Opath->set (strdup(params[1]));
+    bx_options.cmos.OcmosImage->set (1);                // CMOS Image is true
+    }
+  else if (!strcmp(params[0], "time0")) { // Deprectated
+    BX_INFO(("WARNING: time0 directive is deprecated, use clock: instead"));
+    if (num_params != 2) {
+      PARSE_ERR(("%s: time0 directive: wrong # args.", context));
+      }
+    bx_options.clock.Otime0->set (atoi(params[1]));
+    }
+  else if (!strcmp(params[0], "clock")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "sync=", 5)) {
+        bx_options.clock.Osync->set_by_name (&params[i][5]);
+        }
+      else if (!strcmp(params[i], "time0=local")) {
+        bx_options.clock.Otime0->set (BX_CLOCK_TIME0_LOCAL);
+        }
+      else if (!strcmp(params[i], "time0=utc")) {
+        bx_options.clock.Otime0->set (BX_CLOCK_TIME0_UTC);
+        }
+      else if (!strncmp(params[i], "time0=", 6)) {
+        bx_options.clock.Otime0->set (atoi(&params[i][6]));
+        }
+      else {
+        BX_ERROR(("%s: unknown parameter for clock ignored.", context));
+        }
+      }
+    }
+#ifdef MAGIC_BREAKPOINT
+  else if (!strcmp(params[0], "magic_break")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: magic_break directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "enabled=", 8)) {
+      PARSE_ERR(("%s: magic_break directive malformed.", context));
+      }
+    if (params[1][8] == '0') {
+      BX_INFO(("Ignoring magic break points"));
+      bx_dbg.magic_break_enabled = 0;
+      }
+    else if (params[1][8] == '1') {
+      BX_INFO(("Stopping on magic break points"));
+      bx_dbg.magic_break_enabled = 1;
+      }
+    else {
+      PARSE_ERR(("%s: magic_break directive malformed.", context));
+      }
+    }
+#endif
+  else if (!strcmp(params[0], "ne2k")) {
+    int tmp[6];
+    char tmpchar[6];
+    int valid = 0;
+    int n;
+    if (!bx_options.ne2k.Opresent->get ()) {
+      bx_options.ne2k.Oethmod->set_by_name ("null");
+      }
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "ioaddr=", 7)) {
+        bx_options.ne2k.Oioaddr->set (strtoul(&params[i][7], NULL, 16));
+        valid |= 0x01;
+        }
+      else if (!strncmp(params[i], "irq=", 4)) {
+        bx_options.ne2k.Oirq->set (atol(&params[i][4]));
+        valid |= 0x02;
+        }
+      else if (!strncmp(params[i], "mac=", 4)) {
+        n = sscanf(&params[i][4], "%x:%x:%x:%x:%x:%x",
+                   &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5]);
+        if (n != 6) {
+          PARSE_ERR(("%s: ne2k mac address malformed.", context));
+        }
+        for (n=0;n<6;n++)
+          tmpchar[n] = (unsigned char)tmp[n];
+        bx_options.ne2k.Omacaddr->set (tmpchar);
+        valid |= 0x04;
+        }
+      else if (!strncmp(params[i], "ethmod=", 7)) {
+        if (!bx_options.ne2k.Oethmod->set_by_name (strdup(&params[i][7])))
+          PARSE_ERR(("%s: ethernet module '%s' not available", context, strdup(&params[i][7])));
+        }
+      else if (!strncmp(params[i], "ethdev=", 7)) {
+        bx_options.ne2k.Oethdev->set (strdup(&params[i][7]));
+        }
+      else if (!strncmp(params[i], "script=", 7)) {
+        bx_options.ne2k.Oscript->set (strdup(&params[i][7]));
+        }
+      else {
+        PARSE_ERR(("%s: ne2k directive malformed.", context));
+        }
+    }
+    if (!bx_options.ne2k.Opresent->get ()) {
+      if (valid == 0x07) {
+        bx_options.ne2k.Opresent->set (1);
+        }
+      else {
+        PARSE_ERR(("%s: ne2k directive incomplete (ioaddr, irq and mac are required)", context));
+        }
+      }
+    }
+
+  else if (!strcmp(params[0], "load32bitOSImage")) {
+    if ( (num_params!=4) && (num_params!=5) ) {
+      PARSE_ERR(("%s: load32bitOSImage directive: wrong # args.", context));
+      }
+    if (strncmp(params[1], "os=", 3)) {
+      PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+      }
+    if (!strcmp(&params[1][3], "nullkernel")) {
+      bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSNullKernel);
+      }
+    else if (!strcmp(&params[1][3], "linux")) {
+      bx_options.load32bitOSImage.OwhichOS->set (Load32bitOSLinux);
+      }
+    else {
+      PARSE_ERR(("%s: load32bitOSImage: unsupported OS.", context));
+      }
+    if (strncmp(params[2], "path=", 5)) {
+      PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+      }
+    if (strncmp(params[3], "iolog=", 6)) {
+      PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+      }
+    bx_options.load32bitOSImage.Opath->set (strdup(&params[2][5]));
+    bx_options.load32bitOSImage.Oiolog->set (strdup(&params[3][6]));
+    if (num_params == 5) {
+      if (strncmp(params[4], "initrd=", 7)) {
+        PARSE_ERR(("%s: load32bitOSImage: directive malformed.", context));
+        }
+      bx_options.load32bitOSImage.Oinitrd->set (strdup(&params[4][7]));
+      }
+    }
+  else if (!strcmp(params[0], "keyboard_type")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: keyboard_type directive: wrong # args.", context));
+      }
+    if(strcmp(params[1],"xt")==0){
+      bx_options.Okeyboard_type->set (BX_KBD_XT_TYPE);
+      }
+    else if(strcmp(params[1],"at")==0){
+      bx_options.Okeyboard_type->set (BX_KBD_AT_TYPE);
+      }
+    else if(strcmp(params[1],"mf")==0){
+      bx_options.Okeyboard_type->set (BX_KBD_MF_TYPE);
+      }
+    else{
+      PARSE_ERR(("%s: keyboard_type directive: wrong arg %s.", context,params[1]));
+      }
+    }
+
+  else if (!strcmp(params[0], "keyboard_mapping")
+         ||!strcmp(params[0], "keyboardmapping")) {
+    for (i=1; i<num_params; i++) {
+      if (!strncmp(params[i], "enabled=", 8)) {
+        bx_options.keyboard.OuseMapping->set (atol(&params[i][8]));
+        }
+      else if (!strncmp(params[i], "map=", 4)) {
+        bx_options.keyboard.Okeymap->set (strdup(&params[i][4]));
+        }
+      }
+    }
+  else if (!strcmp(params[0], "user_shortcut")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: user_shortcut directive: wrong # args.", context));
+      }
+    if(!strncmp(params[1], "keys=", 4)) {
+      bx_options.Ouser_shortcut->set (strdup(&params[1][5]));
+      }
+    }
+  else if (!strcmp(params[0], "config_interface")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: config_interface directive: wrong # args.", context));
+      }
+    if (!bx_options.Osel_config->set_by_name (params[1]))
+      PARSE_ERR(("%s: config_interface '%s' not available", context, params[1]));
+    }
+  else if (!strcmp(params[0], "display_library")) {
+    if (num_params != 2) {
+      PARSE_ERR(("%s: display_library directive: wrong # args.", context));
+      }
+    if (!bx_options.Osel_displaylib->set_by_name (params[1]))
+      PARSE_ERR(("%s: display library '%s' not available", context, params[1]));
+    }
+  else {
+    PARSE_ERR(( "%s: directive '%s' not understood", context, params[0]));
+    }
+  return 0;
+}
+
+static char *fdtypes[] = {
+  "none", "1_2", "1_44", "2_88", "720k", "360k", "160k", "180k", "320k"
+};
+
+
+int 
+bx_write_floppy_options (FILE *fp, int drive, bx_floppy_options *opt)
+{
+  BX_ASSERT (drive==0 || drive==1);
+  if (opt->Otype->get () == BX_FLOPPY_NONE) {
+    fprintf (fp, "# no floppy%c\n", (char)'a'+drive);
+    return 0;
+  }
+  BX_ASSERT (opt->Otype->get () > BX_FLOPPY_NONE && opt->Otype->get () <= BX_FLOPPY_LAST);
+  fprintf (fp, "floppy%c: %s=\"%s\", status=%s\n", 
+    (char)'a'+drive, 
+    fdtypes[opt->Otype->get () - BX_FLOPPY_NONE],
+    opt->Opath->getptr (),
+    opt->Ostatus->get ()==BX_EJECTED ? "ejected" : "inserted");
+  return 0;
+}
+
+int 
+bx_write_ata_options (FILE *fp, Bit8u channel, bx_ata_options *opt)
+{
+  fprintf (fp, "ata%d: enabled=%d", channel, opt->Opresent->get());
+
+  if (opt->Opresent->get()) {
+    fprintf (fp, ", ioaddr1=0x%x, ioaddr2=0x%x, irq=%d", opt->Oioaddr1->get(), 
+      opt->Oioaddr2->get(), opt->Oirq->get());
+    }
+
+  fprintf (fp, "\n");
+  return 0;
+}
+
+int 
+bx_write_atadevice_options (FILE *fp, Bit8u channel, Bit8u drive, bx_atadevice_options *opt)
+{
+  if (opt->Opresent->get()) {
+    fprintf (fp, "ata%d-%s: ", channel, drive==0?"master":"slave");
+
+    if (opt->Otype->get() == BX_ATA_DEVICE_DISK) {
+      fprintf (fp, "type=disk");
+
+      switch(opt->Omode->get()) {
+        case BX_ATA_MODE_FLAT:
+          fprintf (fp, ", mode=flat");
+          break;
+        case BX_ATA_MODE_CONCAT:
+          fprintf (fp, ", mode=concat");
+          break;
+        case BX_ATA_MODE_EXTDISKSIM:
+          fprintf (fp, ", mode=external");
+          break;
+        case BX_ATA_MODE_DLL_HD:
+          fprintf (fp, ", mode=dll");
+          break;
+        case BX_ATA_MODE_SPARSE:
+          fprintf (fp, ", mode=sparse");
+          break;
+        case BX_ATA_MODE_VMWARE3:
+          fprintf (fp, ", mode=vmware3");
+          break;
+//        case BX_ATA_MODE_SPLIT:
+//          fprintf (fp, ", mode=split");
+//          break;
+        case BX_ATA_MODE_UNDOABLE:
+          fprintf (fp, ", mode=undoable");
+          break;
+        case BX_ATA_MODE_GROWING:
+          fprintf (fp, ", mode=growing");
+          break;
+        case BX_ATA_MODE_VOLATILE:
+          fprintf (fp, ", mode=volatile");
+          break;
+//        case BX_ATA_MODE_Z_UNDOABLE:
+//          fprintf (fp, ", mode=z-undoable");
+//          break;
+//        case BX_ATA_MODE_Z_VOLATILE:
+//          fprintf (fp, ", mode=z-volatile");
+//          break;
+        }
+
+      switch(opt->Otranslation->get()) {
+        case BX_ATA_TRANSLATION_NONE:
+          fprintf (fp, ", translation=none");
+          break;
+        case BX_ATA_TRANSLATION_LBA:
+          fprintf (fp, ", translation=lba");
+          break;
+        case BX_ATA_TRANSLATION_LARGE:
+          fprintf (fp, ", translation=large");
+          break;
+        case BX_ATA_TRANSLATION_RECHS:
+          fprintf (fp, ", translation=rechs");
+          break;
+        case BX_ATA_TRANSLATION_AUTO:
+          fprintf (fp, ", translation=auto");
+          break;
+        }
+
+      fprintf (fp, ", path=\"%s\", cylinders=%d, heads=%d, spt=%d",
+          opt->Opath->getptr(), 
+          opt->Ocylinders->get(), opt->Oheads->get(), opt->Ospt->get());
+
+      if (opt->Ojournal->getptr() != NULL)
+        if ( strcmp(opt->Ojournal->getptr(), "") != 0)
+          fprintf (fp, ", journal=\"%s\"", opt->Ojournal->getptr());
+
+      }
+    else if (opt->Otype->get() == BX_ATA_DEVICE_CDROM) {
+      fprintf (fp, "type=cdrom, path=\"%s\", status=%s", 
+        opt->Opath->getptr(), 
+        opt->Ostatus->get ()==BX_EJECTED ? "ejected" : "inserted");
+      }
+
+    switch(opt->Obiosdetect->get()) {
+      case BX_ATA_BIOSDETECT_NONE:
+        fprintf (fp, ", biosdetect=none");
+        break;
+      case BX_ATA_BIOSDETECT_CMOS:
+        fprintf (fp, ", biosdetect=cmos");
+        break;
+      case BX_ATA_BIOSDETECT_AUTO:
+        fprintf (fp, ", biosdetect=auto");
+        break;
+      }
+    if (strlen(opt->Omodel->getptr())>0) {
+        fprintf (fp, ", model=\"%s\"", opt->Omodel->getptr());
+      }
+
+    fprintf (fp, "\n");
+  }
+  return 0;
+}
+
+int
+bx_write_parport_options (FILE *fp, bx_parport_options *opt, int n)
+{
+  fprintf (fp, "parport%d: enabled=%d", n, opt->Oenabled->get ());
+  if (opt->Oenabled->get ()) {
+    fprintf (fp, ", file=\"%s\"", opt->Ooutfile->getptr ());
+  }
+  fprintf (fp, "\n");
+  return 0;
+}
+
+int
+bx_write_serial_options (FILE *fp, bx_serial_options *opt, int n)
+{
+  fprintf (fp, "com%d: enabled=%d", n, opt->Oenabled->get ());
+  if (opt->Oenabled->get ()) {
+    fprintf (fp, ", dev=\"%s\"", opt->Odev->getptr ());
+  }
+  fprintf (fp, "\n");
+  return 0;
+}
+
+int
+bx_write_usb_options (FILE *fp, bx_usb_options *opt, int n)
+{
+  fprintf (fp, "usb%d: enabled=%d", n, opt->Oenabled->get ());
+  if (opt->Oenabled->get ()) {
+    fprintf (fp, ", ioaddr=0x%04x, irq=%d", opt->Oioaddr->get (),
+      opt->Oirq->get ());
+  }
+  fprintf (fp, "\n");
+  return 0;
+}
+
+int
+bx_write_sb16_options (FILE *fp, bx_sb16_options *opt)
+{
+  if (!opt->Opresent->get ()) {
+    fprintf (fp, "# no sb16\n");
+    return 0;
+  }
+  fprintf (fp, "sb16: midimode=%d, midi=%s, wavemode=%d, wave=%s, loglevel=%d, log=%s, dmatimer=%d\n", opt->Omidimode->get (), opt->Omidifile->getptr (), opt->Owavemode->get (), opt->Owavefile->getptr (), opt->Ologlevel->get (), opt->Ologfile->getptr (), opt->Odmatimer->get ());
+  return 0;
+}
+
+int
+bx_write_ne2k_options (FILE *fp, bx_ne2k_options *opt)
+{
+  if (!opt->Opresent->get ()) {
+    fprintf (fp, "# no ne2k\n");
+    return 0;
+  }
+  char *ptr = opt->Omacaddr->getptr ();
+  fprintf (fp, "ne2k: ioaddr=0x%x, irq=%d, mac=%02x:%02x:%02x:%02x:%02x:%02x, ethmod=%s, ethdev=%s, script=%s\n",
+      opt->Oioaddr->get (), 
+      opt->Oirq->get (),
+      (unsigned int)(0xff & ptr[0]),
+      (unsigned int)(0xff & ptr[1]),
+      (unsigned int)(0xff & ptr[2]),
+      (unsigned int)(0xff & ptr[3]),
+      (unsigned int)(0xff & ptr[4]),
+      (unsigned int)(0xff & ptr[5]),
+      opt->Oethmod->get_choice(opt->Oethmod->get()),
+      opt->Oethdev->getptr (),
+      opt->Oscript->getptr ());
+  return 0;
+}
+
+int
+bx_write_loader_options (FILE *fp, bx_load32bitOSImage_t *opt)
+{
+  if (opt->OwhichOS->get () == 0) {
+    fprintf (fp, "# no loader\n");
+    return 0;
+  }
+  BX_ASSERT(opt->OwhichOS->get () == Load32bitOSLinux || opt->OwhichOS->get () == Load32bitOSNullKernel);
+  fprintf (fp, "load32bitOSImage: os=%s, path=%s, iolog=%s, initrd=%s\n",
+      (opt->OwhichOS->get () == Load32bitOSLinux) ? "linux" : "nullkernel",
+      opt->Opath->getptr (),
+      opt->Oiolog->getptr (),
+      opt->Oinitrd->getptr ());
+  return 0;
+}
+
+int
+bx_write_clock_options (FILE *fp, bx_clock_options *opt)
+{
+  fprintf (fp, "clock: ");
+
+  switch (opt->Osync->get()) {
+    case BX_CLOCK_SYNC_NONE:
+      fprintf (fp, "sync=none");
+      break;
+    case BX_CLOCK_SYNC_REALTIME:
+      fprintf (fp, "sync=realtime");
+      break;
+    case BX_CLOCK_SYNC_SLOWDOWN:
+      fprintf (fp, "sync=slowdown");
+      break;
+    case BX_CLOCK_SYNC_BOTH:
+      fprintf (fp, "sync=both");
+      break;
+    default:
+      BX_PANIC(("Unknown value for sync method"));
+  }
+
+  switch (opt->Otime0->get()) {
+    case 0: break;
+    case BX_CLOCK_TIME0_LOCAL: 
+      fprintf (fp, ", time0=local");
+      break;
+    case BX_CLOCK_TIME0_UTC: 
+      fprintf (fp, ", time0=utc");
+      break;
+    default: 
+      fprintf (fp, ", time0=%u", opt->Otime0->get());
+  }
+
+  fprintf (fp, "\n");
+  return 0;
+}
+
+int
+bx_write_log_options (FILE *fp, bx_log_options *opt)
+{
+  fprintf (fp, "log: %s\n", opt->Ofilename->getptr ());
+  fprintf (fp, "logprefix: %s\n", opt->Oprefix->getptr ());
+  fprintf (fp, "debugger_log: %s\n", opt->Odebugger_filename->getptr ());
+  fprintf (fp, "panic: action=%s\n",
+      io->getaction(logfunctions::get_default_action (LOGLEV_PANIC)));
+  fprintf (fp, "error: action=%s\n",
+      io->getaction(logfunctions::get_default_action (LOGLEV_ERROR)));
+  fprintf (fp, "info: action=%s\n",
+      io->getaction(logfunctions::get_default_action (LOGLEV_INFO)));
+  fprintf (fp, "debug: action=%s\n",
+      io->getaction(logfunctions::get_default_action (LOGLEV_DEBUG)));
+  fprintf (fp, "pass: action=%s\n",
+      io->getaction(logfunctions::get_default_action (LOGLEV_PASS)));
+  return 0;
+}
+
+int
+bx_write_keyboard_options (FILE *fp, bx_keyboard_options *opt)
+{
+  fprintf (fp, "keyboard_mapping: enabled=%d, map=%s\n", opt->OuseMapping->get(), opt->Okeymap->getptr());
+  return 0;
+}
+
+// return values:
+//   0: written ok
+//  -1: failed
+//  -2: already exists, and overwrite was off
+int
+bx_write_configuration (char *rc, int overwrite)
+{
+  BX_INFO (("write configuration to %s\n", rc));
+  // check if it exists.  If so, only proceed if overwrite is set.
+  FILE *fp = fopen (rc, "r");
+  if (fp != NULL) {
+    fclose (fp);
+    if (!overwrite) return -2;
+  }
+  fp = fopen (rc, "w");
+  if (fp == NULL) return -1;
+  // finally it's open and we can start writing.
+  fprintf (fp, "# configuration file generated by Bochs\n");
+  fprintf (fp, "config_interface: %s\n", bx_options.Osel_config->get_choice(bx_options.Osel_config->get()));
+  fprintf (fp, "display_library: %s\n", bx_options.Osel_displaylib->get_choice(bx_options.Osel_displaylib->get()));
+  fprintf (fp, "megs: %d\n", bx_options.memory.Osize->get ());
+  if (strlen (bx_options.rom.Opath->getptr ()) > 0)
+    fprintf (fp, "romimage: file=%s, address=0x%05x\n", bx_options.rom.Opath->getptr(), (unsigned int)bx_options.rom.Oaddress->get ());
+  else
+    fprintf (fp, "# no romimage\n");
+  if (strlen (bx_options.vgarom.Opath->getptr ()) > 0)
+    fprintf (fp, "vgaromimage: %s\n", bx_options.vgarom.Opath->getptr ());
+  else
+    fprintf (fp, "# no vgaromimage\n");
+  int bootdrive = bx_options.Obootdrive->get ();
+  fprintf (fp, "boot: %s\n", (bootdrive==BX_BOOT_FLOPPYA) ? "floppy" : (bootdrive==BX_BOOT_DISKC) ? "disk" : "cdrom");
+  // it would be nice to put this type of function as methods on
+  // the structs like bx_floppy_options::print or something.
+  bx_write_floppy_options (fp, 0, &bx_options.floppya);
+  bx_write_floppy_options (fp, 1, &bx_options.floppyb);
+  for (Bit8u channel=0; channel<BX_MAX_ATA_CHANNEL; channel++) {
+    bx_write_ata_options (fp, channel, &bx_options.ata[channel]);
+    bx_write_atadevice_options (fp, channel, 0, &bx_options.atadevice[channel][0]);
+    bx_write_atadevice_options (fp, channel, 1, &bx_options.atadevice[channel][1]);
+    }
+  if (strlen (bx_options.optrom[0].Opath->getptr ()) > 0)
+    fprintf (fp, "optromimage1: file=%s, address=0x%05x\n", bx_options.optrom[0].Opath->getptr(), (unsigned int)bx_options.optrom[0].Oaddress->get ());
+  if (strlen (bx_options.optrom[1].Opath->getptr ()) > 0)
+    fprintf (fp, "optromimage2: file=%s, address=0x%05x\n", bx_options.optrom[1].Opath->getptr(), (unsigned int)bx_options.optrom[1].Oaddress->get ());
+  if (strlen (bx_options.optrom[2].Opath->getptr ()) > 0)
+    fprintf (fp, "optromimage3: file=%s, address=0x%05x\n", bx_options.optrom[2].Opath->getptr(), (unsigned int)bx_options.optrom[2].Oaddress->get ());
+  if (strlen (bx_options.optrom[3].Opath->getptr ()) > 0)
+    fprintf (fp, "optromimage4: file=%s, address=0x%05x\n", bx_options.optrom[3].Opath->getptr(), (unsigned int)bx_options.optrom[3].Oaddress->get ());
+  bx_write_parport_options (fp, &bx_options.par[0], 1);
+  //bx_write_parport_options (fp, &bx_options.par[1], 2);
+  bx_write_serial_options (fp, &bx_options.com[0], 1);
+  //bx_write_serial_options (fp, &bx_options.com[1], 2);
+  //bx_write_serial_options (fp, &bx_options.com[2], 3);
+  //bx_write_serial_options (fp, &bx_options.com[3], 4);
+  bx_write_usb_options (fp, &bx_options.usb[0], 1);
+  bx_write_sb16_options (fp, &bx_options.sb16);
+  fprintf (fp, "floppy_bootsig_check: disabled=%d\n", bx_options.OfloppySigCheck->get ());
+  fprintf (fp, "vga_update_interval: %u\n", bx_options.Ovga_update_interval->get ());
+  fprintf (fp, "keyboard_serial_delay: %u\n", bx_options.Okeyboard_serial_delay->get ());
+  fprintf (fp, "keyboard_paste_delay: %u\n", bx_options.Okeyboard_paste_delay->get ());
+  fprintf (fp, "floppy_command_delay: %u\n", bx_options.Ofloppy_command_delay->get ());
+  fprintf (fp, "ips: %u\n", bx_options.Oips->get ());
+  fprintf (fp, "text_snapshot_check: %d\n", bx_options.Otext_snapshot_check->get ());
+  fprintf (fp, "mouse: enabled=%d\n", bx_options.Omouse_enabled->get ());
+  fprintf (fp, "private_colormap: enabled=%d\n", bx_options.Oprivate_colormap->get ());
+#if BX_WITH_AMIGAOS
+  fprintf (fp, "fullscreen: enabled=%d\n", bx_options.Ofullscreen->get ());
+  fprintf (fp, "screenmode: name=\"%s\"\n", bx_options.Oscreenmode->getptr ());
+#endif
+  fprintf (fp, "i440fxsupport: enabled=%d\n", bx_options.Oi440FXSupport->get ());
+  bx_write_clock_options (fp, &bx_options.clock);
+  bx_write_ne2k_options (fp, &bx_options.ne2k);
+  fprintf (fp, "newharddrivesupport: enabled=%d\n", bx_options.OnewHardDriveSupport->get ());
+  bx_write_loader_options (fp, &bx_options.load32bitOSImage);
+  bx_write_log_options (fp, &bx_options.log);
+  bx_write_keyboard_options (fp, &bx_options.keyboard);
+  fprintf (fp, "keyboard_type: %s\n", bx_options.Okeyboard_type->get ()==BX_KBD_XT_TYPE?"xt":
+                                       bx_options.Okeyboard_type->get ()==BX_KBD_AT_TYPE?"at":"mf");
+  fprintf (fp, "user_shortcut: keys=%s\n", bx_options.Ouser_shortcut->getptr ());
+  if (strlen (bx_options.cmos.Opath->getptr ()) > 0)
+    fprintf (fp, "cmosimage: %s\n", bx_options.cmos.Opath->getptr());
+  else
+    fprintf (fp, "# no cmosimage\n");
+  fclose (fp);
+  return 0;
+}
+#endif // #if BX_PROVIDE_MAIN
+
+  void
+bx_signal_handler( int signum)
+{
+  // in a multithreaded environment, a signal such as SIGINT can be sent to all
+  // threads.  This function is only intended to handle signals in the
+  // simulator thread.  It will simply return if called from any other thread.
+  // Otherwise the BX_PANIC() below can be called in multiple threads at
+  // once, leading to multiple threads trying to display a dialog box,
+  // leading to GUI deadlock.
+  if (!SIM->is_sim_thread ()) {
+    BX_INFO (("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum));
+    return;
+  }
+#if BX_GUI_SIGHANDLER
+  if (bx_gui_sighandler) {
+    // GUI signal handler gets first priority, if the mask says it's wanted
+    if ((1<<signum) & bx_gui->get_sighandler_mask ()) {
+      bx_gui->sighandler (signum);
+      return;
+    }
+  }
+#endif
+
+#if BX_SHOW_IPS
+  extern unsigned long ips_count;
+
+  if (signum == SIGALRM ) {
+    BX_INFO(("ips = %lu", ips_count));
+    ips_count = 0;
+#ifndef __MINGW32__
+    signal(SIGALRM, bx_signal_handler);
+    alarm( 1 );
+#endif
+    return;
+    }
+#endif
+
+#if BX_GUI_SIGHANDLER
+  if (bx_gui_sighandler) {
+    if ((1<<signum) & bx_gui->get_sighandler_mask ()) {
+      bx_gui->sighandler (signum);
+      return;
+    }
+  }
+#endif
+  BX_PANIC(("SIGNAL %u caught", signum));
+}
+
diff --git a/tools/ioemu/iodev/ne2k.cc b/tools/ioemu/iodev/ne2k.cc
new file mode 100644 (file)
index 0000000..d6e0ac4
--- /dev/null
@@ -0,0 +1,1608 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+#include "bochs.h"
+#if BX_NE2K_SUPPORT
+
+//Never completely fill the ne2k ring so that we never
+// hit the unclear completely full buffer condition.
+#define BX_NE2K_NEVER_FULL_RING (1)
+
+#define LOG_THIS theNE2kDevice->
+
+bx_ne2k_c *theNE2kDevice = NULL;
+
+  int
+libne2k_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theNE2kDevice = new bx_ne2k_c ();
+  bx_devices.pluginNE2kDevice = theNE2kDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theNE2kDevice, BX_PLUGIN_NE2K);
+  return(0); // Success
+}
+
+  void
+libne2k_LTX_plugin_fini(void)
+{
+}
+  
+bx_ne2k_c::bx_ne2k_c(void)
+{
+  put("NE2K");
+  settype(NE2KLOG);
+  s.tx_timer_index = BX_NULL_TIMER_HANDLE;
+}
+
+
+bx_ne2k_c::~bx_ne2k_c(void)
+{
+  // nothing for now
+}
+
+//
+// reset - restore state to power-up, cancelling all i/o
+//
+void
+bx_ne2k_c::reset(unsigned type)
+{
+  BX_DEBUG (("reset"));
+  // Zero out registers and memory
+  memset( & BX_NE2K_THIS s.CR,  0, sizeof(BX_NE2K_THIS s.CR) );
+  memset( & BX_NE2K_THIS s.ISR, 0, sizeof(BX_NE2K_THIS s.ISR));
+  memset( & BX_NE2K_THIS s.IMR, 0, sizeof(BX_NE2K_THIS s.IMR));
+  memset( & BX_NE2K_THIS s.DCR, 0, sizeof(BX_NE2K_THIS s.DCR));
+  memset( & BX_NE2K_THIS s.TCR, 0, sizeof(BX_NE2K_THIS s.TCR));
+  memset( & BX_NE2K_THIS s.TSR, 0, sizeof(BX_NE2K_THIS s.TSR));
+  memset( & BX_NE2K_THIS s.RCR, 0, sizeof(BX_NE2K_THIS s.RCR));
+  memset( & BX_NE2K_THIS s.RSR, 0, sizeof(BX_NE2K_THIS s.RSR));
+  BX_NE2K_THIS s.local_dma  = 0;
+  BX_NE2K_THIS s.page_start = 0;
+  BX_NE2K_THIS s.page_stop  = 0;
+  BX_NE2K_THIS s.bound_ptr  = 0;
+  BX_NE2K_THIS s.tx_page_start = 0;
+  BX_NE2K_THIS s.num_coll   = 0;
+  BX_NE2K_THIS s.tx_bytes   = 0;
+  BX_NE2K_THIS s.fifo       = 0;
+  BX_NE2K_THIS s.remote_dma = 0;
+  BX_NE2K_THIS s.remote_start = 0;
+  BX_NE2K_THIS s.remote_bytes = 0;
+  BX_NE2K_THIS s.tallycnt_0 = 0;
+  BX_NE2K_THIS s.tallycnt_1 = 0;
+  BX_NE2K_THIS s.tallycnt_2 = 0;
+
+  memset( & BX_NE2K_THIS s.physaddr, 0, sizeof(BX_NE2K_THIS s.physaddr));
+  memset( & BX_NE2K_THIS s.mchash, 0, sizeof(BX_NE2K_THIS s.mchash));
+  BX_NE2K_THIS s.curr_page = 0;
+
+  BX_NE2K_THIS s.rempkt_ptr   = 0;
+  BX_NE2K_THIS s.localpkt_ptr = 0;
+  BX_NE2K_THIS s.address_cnt  = 0;
+
+  memset( & BX_NE2K_THIS s.mem, 0, sizeof(BX_NE2K_THIS s.mem));
+  
+  // Set power-up conditions
+  BX_NE2K_THIS s.CR.stop      = 1;
+    BX_NE2K_THIS s.CR.rdma_cmd  = 4;
+  BX_NE2K_THIS s.ISR.reset    = 1;
+  BX_NE2K_THIS s.DCR.longaddr = 1;
+  DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
+}
+
+//
+// read_cr/write_cr - utility routines for handling reads/writes to
+// the Command Register
+//
+Bit32u
+bx_ne2k_c::read_cr(void)
+{
+  Bit32u val = 
+         (((BX_NE2K_THIS s.CR.pgsel    & 0x03) << 6) |
+         ((BX_NE2K_THIS s.CR.rdma_cmd & 0x07) << 3) |
+         (BX_NE2K_THIS s.CR.tx_packet << 2) |
+         (BX_NE2K_THIS s.CR.start     << 1) |
+         (BX_NE2K_THIS s.CR.stop));
+  BX_DEBUG(("read CR returns 0x%08x", val));
+  return val;
+}
+
+void
+bx_ne2k_c::write_cr(Bit32u value)
+{
+  BX_DEBUG(("wrote 0x%02x to CR", value));
+
+  // Validate remote-DMA
+  if ((value & 0x38) == 0x00) {
+    BX_DEBUG(("CR write - invalid rDMA value 0"));
+    value |= 0x20; /* dma_cmd == 4 is a safe default */
+  }
+
+  // Check for s/w reset
+  if (value & 0x01) {
+    BX_NE2K_THIS s.ISR.reset = 1;
+    BX_NE2K_THIS s.CR.stop   = 1;
+  } else {
+    BX_NE2K_THIS s.CR.stop = 0;
+  }
+
+  BX_NE2K_THIS s.CR.rdma_cmd = (value & 0x38) >> 3;
+
+  // If start command issued, the RST bit in the ISR
+  // must be cleared
+  if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) {
+    BX_NE2K_THIS s.ISR.reset = 0;
+  }
+
+  BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
+  BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6;
+
+    // Check for send-packet command
+    if (BX_NE2K_THIS s.CR.rdma_cmd == 3) {
+       // Set up DMA read from receive ring
+       BX_NE2K_THIS s.remote_start = BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.bound_ptr * 256;
+       BX_NE2K_THIS s.remote_bytes = *((Bit16u*) & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]);
+       BX_INFO(("Sending buffer #x%x length %d",
+                 BX_NE2K_THIS s.remote_start,
+                 BX_NE2K_THIS s.remote_bytes));
+    }
+
+  // Check for start-tx
+    if ((value & 0x04) && BX_NE2K_THIS s.TCR.loop_cntl) {
+       if (BX_NE2K_THIS s.TCR.loop_cntl != 1) {
+           BX_INFO(("Loop mode %d not supported.", BX_NE2K_THIS s.TCR.loop_cntl));
+       } else {
+           rx_frame (& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART],
+                     BX_NE2K_THIS s.tx_bytes);
+       }
+    } else if (value & 0x04) {
+    if (BX_NE2K_THIS s.CR.stop || !BX_NE2K_THIS s.CR.start)
+      BX_PANIC(("CR write - tx start, dev in reset"));
+    
+    if (BX_NE2K_THIS s.tx_bytes == 0)
+      BX_PANIC(("CR write - tx start, tx bytes == 0"));
+
+#ifdef notdef    
+    // XXX debug stuff
+    printf("packet tx (%d bytes):\t", BX_NE2K_THIS s.tx_bytes);
+    for (int i = 0; i < BX_NE2K_THIS s.tx_bytes; i++) {
+      printf("%02x ", BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - 
+                               BX_NE2K_MEMSTART + i]);
+      if (i && (((i+1) % 16) == 0)) 
+       printf("\t");
+    }
+    printf("");
+#endif    
+
+    // Send the packet to the system driver
+    BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes);
+
+    // some more debug
+    if (BX_NE2K_THIS s.tx_timer_active)
+      BX_PANIC(("CR write, tx timer still active"));
+    
+    // Schedule a timer to trigger a tx-complete interrupt
+    // The number of microseconds is the bit-time / 10.
+    // The bit-time is the preamble+sfd (64 bits), the
+    // inter-frame gap (96 bits), the CRC (4 bytes), and the
+    // the number of bits in the frame (s.tx_bytes * 8).
+    //
+    bx_pc_system.activate_timer(BX_NE2K_THIS s.tx_timer_index,
+                               (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10,
+                               0); // not continuous
+  }
+
+  // Linux probes for an interrupt by setting up a remote-DMA read
+  // of 0 bytes with remote-DMA completion interrupts enabled.
+  // Detect this here
+  if (BX_NE2K_THIS s.CR.rdma_cmd == 0x01 &&
+      BX_NE2K_THIS s.CR.start &&
+      BX_NE2K_THIS s.remote_bytes == 0) {
+    BX_NE2K_THIS s.ISR.rdma_done = 1;
+    if (BX_NE2K_THIS s.IMR.rdma_inte) {
+      DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+    }
+  }
+}
+
+//
+// chipmem_read/chipmem_write - access the 64K private RAM.
+// The ne2000 memory is accessed through the data port of
+// the asic (offset 0) after setting up a remote-DMA transfer.
+// Both byte and word accesses are allowed.
+// The first 16 bytes contains the MAC address at even locations,
+// and there is 16K of buffer memory starting at 16K
+//
+Bit32u BX_CPP_AttrRegparmN(2)
+bx_ne2k_c::chipmem_read(Bit32u address, unsigned int io_len)
+{
+  Bit32u retval = 0;
+
+  if ((io_len == 2) && (address & 0x1)) 
+    BX_PANIC(("unaligned chipmem word read"));
+
+  // ROM'd MAC address
+  if ((address >=0) && (address <= 31)) {
+    retval = BX_NE2K_THIS s.macaddr[address];
+    if (io_len == 2) {
+      retval |= (BX_NE2K_THIS s.macaddr[address + 1] << 8);
+    }
+    return (retval);
+  }
+
+  if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
+    retval = BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART];
+    if (io_len == 2) {
+      retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] << 8);
+    }
+    return (retval);
+  }
+
+  BX_DEBUG(("out-of-bounds chipmem read, %04X", address));
+
+  return (0xff);
+}
+
+void BX_CPP_AttrRegparmN(3)
+bx_ne2k_c::chipmem_write(Bit32u address, Bit32u value, unsigned io_len)
+{
+  if ((io_len == 2) && (address & 0x1)) 
+    BX_PANIC(("unaligned chipmem word write"));
+
+  if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
+    BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART] = value & 0xff;
+    if (io_len == 2)
+      BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] = value >> 8;
+  } else
+    BX_DEBUG(("out-of-bounds chipmem write, %04X", address));
+}
+
+//
+// asic_read/asic_write - This is the high 16 bytes of i/o space
+// (the lower 16 bytes is for the DS8390). Only two locations
+// are used: offset 0, which is used for data transfer, and
+// offset 0xf, which is used to reset the device.
+// The data transfer port is used to as 'external' DMA to the
+// DS8390. The chip has to have the DMA registers set up, and
+// after that, insw/outsw instructions can be used to move
+// the appropriate number of bytes to/from the device.
+//
+Bit32u BX_CPP_AttrRegparmN(2)
+bx_ne2k_c::asic_read(Bit32u offset, unsigned int io_len)
+{
+  Bit32u retval = 0;
+
+  switch (offset) {
+  case 0x0:  // Data register
+    //
+    // A read remote-DMA command must have been issued,
+    // and the source-address and length registers must  
+    // have been initialised.
+    //
+    if (io_len > BX_NE2K_THIS s.remote_bytes)
+      {
+       BX_ERROR(("ne2K: dma read underrun iolen=%d remote_bytes=%d",io_len,BX_NE2K_THIS s.remote_bytes));
+       //return 0;
+      }
+
+    //BX_INFO(("ne2k read DMA: addr=%4x remote_bytes=%d",BX_NE2K_THIS s.remote_dma,BX_NE2K_THIS s.remote_bytes));
+    retval = chipmem_read(BX_NE2K_THIS s.remote_dma, io_len);
+    //
+    // The 8390 bumps the address and decreases the byte count
+    // by the selected word size after every access, not by
+    // the amount of data requested by the host (io_len).
+    //
+    BX_NE2K_THIS s.remote_dma += (BX_NE2K_THIS s.DCR.wdsize + 1);
+    if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
+      BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
+    }
+    // keep s.remote_bytes from underflowing
+    if (BX_NE2K_THIS s.remote_bytes > 1)
+      BX_NE2K_THIS s.remote_bytes -= (BX_NE2K_THIS s.DCR.wdsize + 1);
+    else
+      BX_NE2K_THIS s.remote_bytes = 0;
+
+       // If all bytes have been written, signal remote-DMA complete
+       if (BX_NE2K_THIS s.remote_bytes == 0) {
+           BX_NE2K_THIS s.ISR.rdma_done = 1;
+           if (BX_NE2K_THIS s.IMR.rdma_inte) {
+               DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+           }
+       }
+    break;
+
+  case 0xf:  // Reset register
+    theNE2kDevice->reset(BX_RESET_SOFTWARE);
+    break;
+
+  default:
+    BX_INFO(("asic read invalid address %04x", (unsigned) offset));
+    break;
+  }
+
+  return (retval);
+}
+
+void
+bx_ne2k_c::asic_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+  BX_DEBUG(("asic write addr=0x%02x, value=0x%04x", (unsigned) offset, (unsigned) value));
+  switch (offset) {
+  case 0x0:  // Data register - see asic_read for a description
+
+    if ((io_len == 2) && (BX_NE2K_THIS s.DCR.wdsize == 0)) {
+      BX_PANIC(("dma write length 2 on byte mode operation"));
+      break;
+    }
+
+    if (BX_NE2K_THIS s.remote_bytes == 0)
+      BX_PANIC(("ne2K: dma write, byte count 0"));
+
+    chipmem_write(BX_NE2K_THIS s.remote_dma, value, io_len);
+    // is this right ??? asic_read uses DCR.wordsize
+    BX_NE2K_THIS s.remote_dma   += io_len;
+    if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
+      BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
+    }
+
+    BX_NE2K_THIS s.remote_bytes -= io_len;
+    if (BX_NE2K_THIS s.remote_bytes > BX_NE2K_MEMSIZ)
+      BX_NE2K_THIS s.remote_bytes = 0;
+
+    // If all bytes have been written, signal remote-DMA complete
+    if (BX_NE2K_THIS s.remote_bytes == 0) {
+      BX_NE2K_THIS s.ISR.rdma_done = 1;
+      if (BX_NE2K_THIS s.IMR.rdma_inte) {
+         DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+      }
+    }
+    break;
+
+  case 0xf:  // Reset register
+    theNE2kDevice->reset(BX_RESET_SOFTWARE);
+    break;
+
+  default: // this is invalid, but happens under win95 device detection
+    BX_INFO(("asic write invalid address %04x, ignoring", (unsigned) offset));
+    break ;
+  }
+}
+
+//
+// page0_read/page0_write - These routines handle reads/writes to
+// the 'zeroth' page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page0_read(Bit32u offset, unsigned int io_len)
+{
+  BX_DEBUG(("page 0 read from port %04x, len=%u", (unsigned) offset,
+          (unsigned) io_len));
+  if (io_len > 1) {
+    BX_ERROR(("bad length! page 0 read from port %04x, len=%u", (unsigned) offset,
+             (unsigned) io_len)); /* encountered with win98 hardware probe */
+       return 0;
+  }
+
+
+  switch (offset) {
+  case 0x0:  // CR
+    return (read_cr());
+    break;
+    
+  case 0x1:  // CLDA0
+    return (BX_NE2K_THIS s.local_dma & 0xff);
+    break;
+
+  case 0x2:  // CLDA1
+    return (BX_NE2K_THIS s.local_dma >> 8);
+    break;
+
+  case 0x3:  // BNRY
+    return (BX_NE2K_THIS s.bound_ptr);
+    break;
+
+  case 0x4:  // TSR
+    return ((BX_NE2K_THIS s.TSR.ow_coll    << 7) |
+           (BX_NE2K_THIS s.TSR.cd_hbeat   << 6) |
+           (BX_NE2K_THIS s.TSR.fifo_ur    << 5) |
+           (BX_NE2K_THIS s.TSR.no_carrier << 4) |
+           (BX_NE2K_THIS s.TSR.aborted    << 3) |
+           (BX_NE2K_THIS s.TSR.collided   << 2) |
+           (BX_NE2K_THIS s.TSR.tx_ok));
+    break;
+
+  case 0x5:  // NCR
+    return (BX_NE2K_THIS s.num_coll);
+    break;
+    
+  case 0x6:  // FIFO
+    // reading FIFO is only valid in loopback mode
+    BX_ERROR(("reading FIFO not supported yet"));
+    return (BX_NE2K_THIS s.fifo);
+    break;
+
+  case 0x7:  // ISR
+    return ((BX_NE2K_THIS s.ISR.reset     << 7) |
+           (BX_NE2K_THIS s.ISR.rdma_done << 6) |
+           (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
+           (BX_NE2K_THIS s.ISR.overwrite << 4) |
+           (BX_NE2K_THIS s.ISR.tx_err    << 3) |
+           (BX_NE2K_THIS s.ISR.rx_err    << 2) |
+           (BX_NE2K_THIS s.ISR.pkt_tx    << 1) |
+           (BX_NE2K_THIS s.ISR.pkt_rx));
+    break;
+    
+  case 0x8:  // CRDA0
+    return (BX_NE2K_THIS s.remote_dma & 0xff);
+    break;
+
+  case 0x9:  // CRDA1
+    return (BX_NE2K_THIS s.remote_dma >> 8);
+    break;
+
+  case 0xa:  // reserved
+    BX_INFO(("reserved read - page 0, 0xa"));
+    return (0xff);
+    break;
+
+  case 0xb:  // reserved
+    BX_INFO(("reserved read - page 0, 0xb"));
+    return (0xff);
+    break;
+    
+  case 0xc:  // RSR
+    return ((BX_NE2K_THIS s.RSR.deferred    << 7) |
+           (BX_NE2K_THIS s.RSR.rx_disabled << 6) |
+           (BX_NE2K_THIS s.RSR.rx_mbit     << 5) |
+           (BX_NE2K_THIS s.RSR.rx_missed   << 4) |
+           (BX_NE2K_THIS s.RSR.fifo_or     << 3) |
+           (BX_NE2K_THIS s.RSR.bad_falign  << 2) |
+           (BX_NE2K_THIS s.RSR.bad_crc     << 1) |
+           (BX_NE2K_THIS s.RSR.rx_ok));
+    break;
+    
+  case 0xd:  // CNTR0
+    return (BX_NE2K_THIS s.tallycnt_0);
+    break;
+
+  case 0xe:  // CNTR1
+    return (BX_NE2K_THIS s.tallycnt_1);
+    break;
+
+  case 0xf:  // CNTR2
+    return (BX_NE2K_THIS s.tallycnt_2);
+    break;
+
+  default:
+    BX_PANIC(("page 0 offset %04x out of range", (unsigned) offset));
+  }
+
+  return(0);
+}
+
+void
+bx_ne2k_c::page0_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+  BX_DEBUG(("page 0 write to port %04x, len=%u", (unsigned) offset,
+          (unsigned) io_len));
+
+  // It appears to be a common practice to use outw on page0 regs...
+
+  // break up outw into two outb's
+  if (io_len == 2) {
+    page0_write(offset, (value & 0xff), 1);
+    page0_write(offset + 1, ((value >> 8) & 0xff), 1);
+    return;
+  }
+
+  switch (offset) {
+  case 0x0:  // CR
+    write_cr(value);
+    break;
+
+  case 0x1:  // PSTART
+    BX_NE2K_THIS s.page_start = value;
+    break;
+
+  case 0x2:  // PSTOP
+       // BX_INFO(("Writing to PSTOP: %02x", value));
+    BX_NE2K_THIS s.page_stop = value;
+    break;
+
+  case 0x3:  // BNRY
+    BX_NE2K_THIS s.bound_ptr = value;
+    break;
+
+  case 0x4:  // TPSR
+    BX_NE2K_THIS s.tx_page_start = value;
+    break;
+
+  case 0x5:  // TBCR0
+    // Clear out low byte and re-insert
+    BX_NE2K_THIS s.tx_bytes &= 0xff00;
+    BX_NE2K_THIS s.tx_bytes |= (value & 0xff);
+    break;
+
+  case 0x6:  // TBCR1
+    // Clear out high byte and re-insert
+    BX_NE2K_THIS s.tx_bytes &= 0x00ff;
+    BX_NE2K_THIS s.tx_bytes |= ((value & 0xff) << 8);
+    break;
+
+  case 0x7:  // ISR
+    value &= 0x7f;  // clear RST bit - status-only bit
+    // All other values are cleared iff the ISR bit is 1
+    BX_NE2K_THIS s.ISR.pkt_rx    &= ~((bx_bool)((value & 0x01) == 0x01));
+    BX_NE2K_THIS s.ISR.pkt_tx    &= ~((bx_bool)((value & 0x02) == 0x02));
+    BX_NE2K_THIS s.ISR.rx_err    &= ~((bx_bool)((value & 0x04) == 0x04));
+    BX_NE2K_THIS s.ISR.tx_err    &= ~((bx_bool)((value & 0x08) == 0x08));
+    BX_NE2K_THIS s.ISR.overwrite &= ~((bx_bool)((value & 0x10) == 0x10));
+    BX_NE2K_THIS s.ISR.cnt_oflow &= ~((bx_bool)((value & 0x20) == 0x20));
+    BX_NE2K_THIS s.ISR.rdma_done &= ~((bx_bool)((value & 0x40) == 0x40));
+    value = ((BX_NE2K_THIS s.ISR.rdma_done << 6) |
+             (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
+             (BX_NE2K_THIS s.ISR.overwrite << 4) |
+             (BX_NE2K_THIS s.ISR.tx_err    << 3) |
+             (BX_NE2K_THIS s.ISR.rx_err    << 2) |
+             (BX_NE2K_THIS s.ISR.pkt_tx    << 1) |
+             (BX_NE2K_THIS s.ISR.pkt_rx));
+    value &= ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
+              (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
+              (BX_NE2K_THIS s.IMR.overw_inte << 4) |
+              (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
+              (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
+              (BX_NE2K_THIS s.IMR.tx_inte << 1) |
+              (BX_NE2K_THIS s.IMR.rx_inte));
+    if (value == 0)
+      DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
+    break;
+
+  case 0x8:  // RSAR0
+    // Clear out low byte and re-insert
+    BX_NE2K_THIS s.remote_start &= 0xff00;
+    BX_NE2K_THIS s.remote_start |= (value & 0xff);
+    BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
+    break;
+
+  case 0x9:  // RSAR1
+    // Clear out high byte and re-insert
+    BX_NE2K_THIS s.remote_start &= 0x00ff;
+    BX_NE2K_THIS s.remote_start |= ((value & 0xff) << 8);
+    BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
+    break;
+
+  case 0xa:  // RBCR0
+    // Clear out low byte and re-insert
+    BX_NE2K_THIS s.remote_bytes &= 0xff00;
+    BX_NE2K_THIS s.remote_bytes |= (value & 0xff);
+    break;
+
+  case 0xb:  // RBCR1
+    // Clear out high byte and re-insert
+    BX_NE2K_THIS s.remote_bytes &= 0x00ff;
+    BX_NE2K_THIS s.remote_bytes |= ((value & 0xff) << 8);
+    break;
+
+  case 0xc:  // RCR
+    // Check if the reserved bits are set
+    if (value & 0xc0)
+      BX_INFO(("RCR write, reserved bits set"));
+
+    // Set all other bit-fields
+    BX_NE2K_THIS s.RCR.errors_ok = ((value & 0x01) == 0x01);
+    BX_NE2K_THIS s.RCR.runts_ok  = ((value & 0x02) == 0x02);
+    BX_NE2K_THIS s.RCR.broadcast = ((value & 0x04) == 0x04);
+    BX_NE2K_THIS s.RCR.multicast = ((value & 0x08) == 0x08);
+    BX_NE2K_THIS s.RCR.promisc   = ((value & 0x10) == 0x10);
+    BX_NE2K_THIS s.RCR.monitor   = ((value & 0x20) == 0x20);
+
+    // Monitor bit is a little suspicious...
+    if (value & 0x20)
+      BX_INFO(("RCR write, monitor bit set!"));
+    break;
+
+  case 0xd:  // TCR
+    // Check reserved bits
+    if (value & 0xe0)
+      BX_ERROR(("TCR write, reserved bits set"));
+
+    // Test loop mode (not supported)
+    if (value & 0x06) {
+      BX_NE2K_THIS s.TCR.loop_cntl = (value & 0x6) >> 1;
+      BX_INFO(("TCR write, loop mode %d not supported", BX_NE2K_THIS s.TCR.loop_cntl));
+    } else {
+      BX_NE2K_THIS s.TCR.loop_cntl = 0;
+    }
+
+    // Inhibit-CRC not supported.
+    if (value & 0x01)
+      BX_PANIC(("TCR write, inhibit-CRC not supported"));
+
+    // Auto-transmit disable very suspicious
+    if (value & 0x08)
+      BX_PANIC(("TCR write, auto transmit disable not supported"));
+
+    // Allow collision-offset to be set, although not used
+    BX_NE2K_THIS s.TCR.coll_prio = ((value & 0x08) == 0x08);
+    break;
+
+  case 0xe:  // DCR
+    // the loopback mode is not suppported yet
+    if (!(value & 0x08)) {
+      BX_ERROR(("DCR write, loopback mode selected"));
+    }
+    // It is questionable to set longaddr and auto_rx, since they
+    // aren't supported on the ne2000. Print a warning and continue
+    if (value & 0x04)
+      BX_INFO(("DCR write - LAS set ???"));
+    if (value & 0x10)
+      BX_INFO(("DCR write - AR set ???"));
+
+    // Set other values.
+    BX_NE2K_THIS s.DCR.wdsize   = ((value & 0x01) == 0x01);
+    BX_NE2K_THIS s.DCR.endian   = ((value & 0x02) == 0x02);
+    BX_NE2K_THIS s.DCR.longaddr = ((value & 0x04) == 0x04); // illegal ?
+    BX_NE2K_THIS s.DCR.loop     = ((value & 0x08) == 0x08);
+    BX_NE2K_THIS s.DCR.auto_rx  = ((value & 0x10) == 0x10); // also illegal ?
+    BX_NE2K_THIS s.DCR.fifo_size = (value & 0x50) >> 5;
+    break;
+
+  case 0xf:  // IMR
+    // Check for reserved bit
+    if (value & 0x80)
+      BX_PANIC(("IMR write, reserved bit set"));
+
+    // Set other values
+    BX_NE2K_THIS s.IMR.rx_inte    = ((value & 0x01) == 0x01);
+    BX_NE2K_THIS s.IMR.tx_inte    = ((value & 0x02) == 0x02);
+    BX_NE2K_THIS s.IMR.rxerr_inte = ((value & 0x04) == 0x04);
+    BX_NE2K_THIS s.IMR.txerr_inte = ((value & 0x08) == 0x08);
+    BX_NE2K_THIS s.IMR.overw_inte = ((value & 0x10) == 0x10);
+    BX_NE2K_THIS s.IMR.cofl_inte  = ((value & 0x20) == 0x20);
+    BX_NE2K_THIS s.IMR.rdma_inte  = ((value & 0x40) == 0x40);
+    break;
+
+  default:
+    BX_PANIC(("page 0 write, bad offset %0x", offset));
+  }
+}
+
+
+//
+// page1_read/page1_write - These routines handle reads/writes to
+// the first page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page1_read(Bit32u offset, unsigned int io_len)
+{
+  BX_DEBUG(("page 1 read from port %04x, len=%u", (unsigned) offset,
+          (unsigned) io_len));
+  if (io_len > 1)
+    BX_PANIC(("bad length! page 1 read from port %04x, len=%u", (unsigned) offset,
+             (unsigned) io_len));
+
+  switch (offset) {
+  case 0x0:  // CR
+    return (read_cr());
+    break;
+    
+  case 0x1:  // PAR0-5
+  case 0x2:
+  case 0x3:
+  case 0x4:
+  case 0x5:
+  case 0x6:
+    return (BX_NE2K_THIS s.physaddr[offset - 1]);
+    break;
+
+  case 0x7:  // CURR
+      BX_DEBUG(("returning current page: %02x", (BX_NE2K_THIS s.curr_page)));
+    return (BX_NE2K_THIS s.curr_page);
+
+  case 0x8:  // MAR0-7
+  case 0x9:
+  case 0xa:
+  case 0xb:
+  case 0xc:
+  case 0xd:
+  case 0xe:
+  case 0xf:
+    return (BX_NE2K_THIS s.mchash[offset - 8]);
+    break;
+
+  default:
+    BX_PANIC(("page 1 r offset %04x out of range", (unsigned) offset));
+  }
+
+  return (0);
+}
+
+void
+bx_ne2k_c::page1_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+  BX_DEBUG(("page 1 w offset %04x", (unsigned) offset));
+  switch (offset) {
+  case 0x0:  // CR
+    write_cr(value);
+    break;  
+
+  case 0x1:  // PAR0-5
+  case 0x2:
+  case 0x3:
+  case 0x4:
+  case 0x5:
+  case 0x6:
+    BX_NE2K_THIS s.physaddr[offset - 1] = value;
+    break;
+    
+  case 0x7:  // CURR
+    BX_NE2K_THIS s.curr_page = value;
+    break;
+
+  case 0x8:  // MAR0-7
+  case 0x9:
+  case 0xa:
+  case 0xb:
+  case 0xc:
+  case 0xd:
+  case 0xe:
+  case 0xf:
+    BX_NE2K_THIS s.mchash[offset - 8] = value;
+    break;
+
+  default:
+    BX_PANIC(("page 1 w offset %04x out of range", (unsigned) offset));
+  }  
+}
+
+
+//
+// page2_read/page2_write - These routines handle reads/writes to
+// the second page of the DS8390 register file
+//
+Bit32u
+bx_ne2k_c::page2_read(Bit32u offset, unsigned int io_len)
+{
+  BX_DEBUG(("page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len));
+
+  if (io_len > 1)
+    BX_PANIC(("bad length!  page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len));
+
+  switch (offset) {
+  case 0x0:  // CR
+    return (read_cr());
+    break;
+
+  case 0x1:  // PSTART
+    return (BX_NE2K_THIS s.page_start);
+    break;
+
+  case 0x2:  // PSTOP
+    return (BX_NE2K_THIS s.page_stop);
+    break;
+
+  case 0x3:  // Remote Next-packet pointer
+    return (BX_NE2K_THIS s.rempkt_ptr);
+    break;
+
+  case 0x4:  // TPSR
+    return (BX_NE2K_THIS s.tx_page_start);
+    break;
+
+  case 0x5:  // Local Next-packet pointer
+    return (BX_NE2K_THIS s.localpkt_ptr);
+    break;
+
+  case 0x6:  // Address counter (upper)
+    return (BX_NE2K_THIS s.address_cnt >> 8);
+    break;
+
+  case 0x7:  // Address counter (lower)
+    return (BX_NE2K_THIS s.address_cnt & 0xff);
+    break;
+
+  case 0x8:  // Reserved
+  case 0x9:
+  case 0xa:
+  case 0xb:
+    BX_ERROR(("reserved read - page 2, 0x%02x", (unsigned) offset));
+    return (0xff);
+    break;
+
+  case 0xc:  // RCR
+    return ((BX_NE2K_THIS s.RCR.monitor   << 5) |
+           (BX_NE2K_THIS s.RCR.promisc   << 4) |
+           (BX_NE2K_THIS s.RCR.multicast << 3) |
+           (BX_NE2K_THIS s.RCR.broadcast << 2) |
+           (BX_NE2K_THIS s.RCR.runts_ok  << 1) |
+           (BX_NE2K_THIS s.RCR.errors_ok));
+    break;
+
+  case 0xd:  // TCR
+    return ((BX_NE2K_THIS s.TCR.coll_prio   << 4) |
+           (BX_NE2K_THIS s.TCR.ext_stoptx  << 3) |
+           ((BX_NE2K_THIS s.TCR.loop_cntl & 0x3) << 1) |
+           (BX_NE2K_THIS s.TCR.crc_disable));
+    break;
+
+  case 0xe:  // DCR
+    return (((BX_NE2K_THIS s.DCR.fifo_size & 0x3) << 5) |
+           (BX_NE2K_THIS s.DCR.auto_rx  << 4) |
+           (BX_NE2K_THIS s.DCR.loop     << 3) |
+           (BX_NE2K_THIS s.DCR.longaddr << 2) |
+           (BX_NE2K_THIS s.DCR.endian   << 1) |
+           (BX_NE2K_THIS s.DCR.wdsize));
+    break;
+
+  case 0xf:  // IMR
+    return ((BX_NE2K_THIS s.IMR.rdma_inte  << 6) |
+           (BX_NE2K_THIS s.IMR.cofl_inte  << 5) |
+           (BX_NE2K_THIS s.IMR.overw_inte << 4) |
+           (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
+           (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
+           (BX_NE2K_THIS s.IMR.tx_inte    << 1) |
+           (BX_NE2K_THIS s.IMR.rx_inte));
+    break;
+
+  default:
+    BX_PANIC(("page 2 offset %04x out of range", (unsigned) offset));
+  }
+
+  return (0);
+};
+
+void
+bx_ne2k_c::page2_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+  // Maybe all writes here should be BX_PANIC()'d, since they
+  // affect internal operation, but let them through for now
+  // and print a warning.
+  if (offset != 0)
+    BX_ERROR(("page 2 write ?"));
+
+  switch (offset) {
+  case 0x0:  // CR
+    write_cr(value);
+    break; 
+
+  case 0x1:  // CLDA0
+    // Clear out low byte and re-insert
+    BX_NE2K_THIS s.local_dma &= 0xff00;
+    BX_NE2K_THIS s.local_dma |= (value & 0xff);
+    break;
+
+  case 0x2:  // CLDA1
+    // Clear out high byte and re-insert
+    BX_NE2K_THIS s.local_dma &= 0x00ff;
+    BX_NE2K_THIS s.local_dma |= ((value & 0xff) << 8);
+    break;
+
+  case 0x3:  // Remote Next-pkt pointer
+    BX_NE2K_THIS s.rempkt_ptr = value;
+    break;
+
+  case 0x4:
+    BX_PANIC(("page 2 write to reserved offset 4"));
+    break;
+
+  case 0x5:  // Local Next-packet pointer
+    BX_NE2K_THIS s.localpkt_ptr = value;
+    break;
+
+  case 0x6:  // Address counter (upper)
+    // Clear out high byte and re-insert
+    BX_NE2K_THIS s.address_cnt &= 0x00ff;
+    BX_NE2K_THIS s.address_cnt |= ((value & 0xff) << 8);
+    break;
+
+  case 0x7:  // Address counter (lower)
+    // Clear out low byte and re-insert
+    BX_NE2K_THIS s.address_cnt &= 0xff00;
+    BX_NE2K_THIS s.address_cnt |= (value & 0xff);
+    break;
+
+  case 0x8:
+  case 0x9:
+  case 0xa:
+  case 0xb:
+  case 0xc:
+  case 0xd:
+  case 0xe:
+  case 0xf:
+    BX_PANIC(("page 2 write to reserved offset %0x", offset));
+    break;
+   
+  default:
+    BX_PANIC(("page 2 write, illegal offset %0x", offset));
+    break;
+  }
+}
+  
+//
+// page3_read/page3_write - writes to this page are illegal
+//
+Bit32u
+bx_ne2k_c::page3_read(Bit32u offset, unsigned int io_len)
+{
+  BX_PANIC(("page 3 read attempted"));
+  return (0);
+}
+
+void
+bx_ne2k_c::page3_write(Bit32u offset, Bit32u value, unsigned io_len)
+{
+  BX_PANIC(("page 3 write attempted"));
+}
+
+//
+// tx_timer_handler/tx_timer
+//
+void
+bx_ne2k_c::tx_timer_handler(void *this_ptr)
+{
+  bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+
+  class_ptr->tx_timer();
+}
+
+void
+bx_ne2k_c::tx_timer(void)
+{
+  BX_DEBUG(("tx_timer"));
+  BX_NE2K_THIS s.TSR.tx_ok = 1;
+  // Generate an interrupt if not masked and not one in progress
+  if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
+    BX_NE2K_THIS s.ISR.pkt_tx = 1;
+    DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+  }
+  BX_NE2K_THIS s.tx_timer_active = 0;
+}
+
+
+//
+// read_handler/read - i/o 'catcher' function called from BOCHS
+// mainline when the CPU attempts a read in the i/o space registered
+// by this ne2000 instance
+//
+Bit32u
+bx_ne2k_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_NE2K_SMF
+  bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+Bit32u
+bx_ne2k_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_NE2K_SMF
+  BX_DEBUG(("read addr %x, len %d", address, io_len));
+  Bit32u retval = 0;
+  int offset = address - BX_NE2K_THIS s.base_address;
+
+  if (offset >= 0x10) {
+    retval = asic_read(offset - 0x10, io_len);
+  } else {
+    switch (BX_NE2K_THIS s.CR.pgsel) {
+    case 0x00:
+      retval = page0_read(offset, io_len);
+      break;
+
+    case 0x01:
+      retval = page1_read(offset, io_len);
+      break;
+
+    case 0x02:
+      retval = page2_read(offset, io_len);
+      break;
+
+    case 0x03:
+      retval = page3_read(offset, io_len);
+      break;
+
+    default:
+      BX_PANIC(("ne2K: unknown value of pgsel in read - %d",
+              BX_NE2K_THIS s.CR.pgsel));
+    }
+  }
+
+  return (retval);
+}
+
+//
+// write_handler/write - i/o 'catcher' function called from BOCHS
+// mainline when the CPU attempts a write in the i/o space registered
+// by this ne2000 instance
+//
+void
+bx_ne2k_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, 
+                        unsigned io_len)
+{
+#if !BX_USE_NE2K_SMF
+  bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
+  
+  class_ptr->write(address, value, io_len);
+}
+
+void
+bx_ne2k_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_NE2K_SMF
+  BX_DEBUG(("write with length %d", io_len));
+  int offset = address - BX_NE2K_THIS s.base_address;
+
+  //
+  // The high 16 bytes of i/o space are for the ne2000 asic -
+  //  the low 16 bytes are for the DS8390, with the current
+  //  page being selected by the PS0,PS1 registers in the
+  //  command register
+  //
+  if (offset >= 0x10) {
+    asic_write(offset - 0x10, value, io_len);
+  } else {
+    switch (BX_NE2K_THIS s.CR.pgsel) {
+    case 0x00:
+      page0_write(offset, value, io_len);
+      break;
+
+    case 0x01:
+      page1_write(offset, value, io_len);
+      break;
+
+    case 0x02:
+      page2_write(offset, value, io_len);
+      break;
+
+    case 0x03:
+      page3_write(offset, value, io_len);
+      break;
+
+    default:
+      BX_PANIC(("ne2K: unknown value of pgsel in write - %d",
+              BX_NE2K_THIS s.CR.pgsel));
+    }
+  }
+}
+
+
+/*
+ * mcast_index() - return the 6-bit index into the multicast
+ * table. Stolen unashamedly from FreeBSD's if_ed.c
+ */
+unsigned
+bx_ne2k_c::mcast_index(const void *dst)
+{
+#define POLYNOMIAL 0x04c11db6
+  unsigned long crc = 0xffffffffL;
+  int carry, i, j;
+  unsigned char b;
+  unsigned char *ep = (unsigned char *) dst;
+
+  for (i = 6; --i >= 0;) {
+    b = *ep++;
+    for (j = 8; --j >= 0;) {
+      carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+      crc <<= 1;
+      b >>= 1;
+      if (carry)
+       crc = ((crc ^ POLYNOMIAL) | carry);
+    }
+  }
+  return (crc >> 26);
+#undef POLYNOMIAL
+}
+
+/*
+ * Callback from the eth system driver when a frame has arrived
+ */
+void
+bx_ne2k_c::rx_handler(void *arg, const void *buf, unsigned len)
+{
+    // BX_DEBUG(("rx_handler with length %d", len));
+  bx_ne2k_c *class_ptr = (bx_ne2k_c *) arg;
+  
+  class_ptr->rx_frame(buf, len);
+}
+
+/*
+ * rx_frame() - called by the platform-specific code when an
+ * ethernet frame has been received. The destination address
+ * is tested to see if it should be accepted, and if the
+ * rx ring has enough room, it is copied into it and
+ * the receive process is updated
+ */
+void
+bx_ne2k_c::rx_frame(const void *buf, unsigned io_len)
+{
+  unsigned pages;
+  unsigned avail;
+  unsigned idx;
+  int wrapped;
+  int nextpage;
+  unsigned char pkthdr[4];
+  unsigned char *pktbuf = (unsigned char *) buf;
+  unsigned char *startptr;
+  static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+  BX_DEBUG(("rx_frame with length %d", io_len));
+
+
+  if ((BX_NE2K_THIS s.CR.stop != 0) ||
+      (BX_NE2K_THIS s.page_start == 0) ||
+      ((BX_NE2K_THIS s.DCR.loop == 0) &&
+       (BX_NE2K_THIS s.TCR.loop_cntl != 0))) {
+
+    return;
+  }
+
+  // Add the pkt header + CRC to the length, and work
+  // out how many 256-byte pages the frame would occupy
+  pages = (io_len + 4 + 4 + 255)/256;
+
+  if (BX_NE2K_THIS s.curr_page < BX_NE2K_THIS s.bound_ptr) {
+    avail = BX_NE2K_THIS s.bound_ptr - BX_NE2K_THIS s.curr_page;    
+  } else {
+    avail = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start) -
+      (BX_NE2K_THIS s.curr_page - BX_NE2K_THIS s.bound_ptr);
+    wrapped = 1;
+  }
+
+  // Avoid getting into a buffer overflow condition by not attempting
+  // to do partial receives. The emulation to handle this condition
+  // seems particularly painful.
+  if ((avail < pages) 
+#if BX_NE2K_NEVER_FULL_RING
+      || (avail == pages)
+#endif
+      ) {
+    return;
+  }
+
+  if ((io_len < 60) && !BX_NE2K_THIS s.RCR.runts_ok) {
+    BX_DEBUG(("rejected small packet, length %d", io_len));
+    return;
+  }
+
+  // Do address filtering if not in promiscuous mode
+  if (! BX_NE2K_THIS s.RCR.promisc) {
+    if (!memcmp(buf, bcast_addr, 6)) {
+      if (!BX_NE2K_THIS s.RCR.broadcast) {
+       return;
+      }
+    } else if (pktbuf[0] & 0x01) {
+       if (! BX_NE2K_THIS s.RCR.multicast) {
+           return;
+       }
+      idx = mcast_index(buf);
+      if (!(BX_NE2K_THIS s.mchash[idx >> 3] & (1 << (idx & 0x7)))) {
+       return;
+      }
+    } else if (0 != memcmp(buf, BX_NE2K_THIS s.physaddr, 6)) {
+      return;
+    }
+  } else {
+      BX_DEBUG(("rx_frame promiscuous receive"));
+  }
+
+//    BX_INFO(("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x",
+//        io_len,
+//        pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5],
+//        pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]));
+
+  nextpage = BX_NE2K_THIS s.curr_page + pages;
+  if (nextpage >= BX_NE2K_THIS s.page_stop) {
+    nextpage -= BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start;
+  }
+
+  // Setup packet header
+  pkthdr[0] = 0;       // rx status - old behavior
+  pkthdr[0] = 1;        // Probably better to set it all the time
+                        // rather than set it to 0, which is clearly wrong.
+  if (pktbuf[0] & 0x01) {
+    pkthdr[0] |= 0x20;  // rx status += multicast packet
+  }
+  pkthdr[1] = nextpage;        // ptr to next packet
+  pkthdr[2] = (io_len + 4) & 0xff;     // length-low
+  pkthdr[3] = (io_len + 4) >> 8;       // length-hi
+
+  // copy into buffer, update curpage, and signal interrupt if config'd
+  startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.curr_page * 256 -
+                              BX_NE2K_MEMSTART];
+  if ((nextpage > BX_NE2K_THIS s.curr_page) ||
+      ((BX_NE2K_THIS s.curr_page + pages) == BX_NE2K_THIS s.page_stop)) {
+    memcpy(startptr, pkthdr, 4);
+    memcpy(startptr + 4, buf, io_len);
+    BX_NE2K_THIS s.curr_page = nextpage;
+  } else {
+    int endbytes = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.curr_page) 
+      * 256;
+    memcpy(startptr, pkthdr, 4);
+    memcpy(startptr + 4, buf, endbytes - 4);
+    startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.page_start * 256 -
+                                BX_NE2K_MEMSTART];
+    memcpy(startptr, (void *)(pktbuf + endbytes - 4),
+          io_len - endbytes + 8);    
+    BX_NE2K_THIS s.curr_page = nextpage;
+  }
+  
+  BX_NE2K_THIS s.RSR.rx_ok = 1;
+  if (pktbuf[0] & 0x80) {
+    BX_NE2K_THIS s.RSR.rx_mbit = 1;
+  }
+
+  BX_NE2K_THIS s.ISR.pkt_rx = 1;
+
+  if (BX_NE2K_THIS s.IMR.rx_inte) {
+    DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
+  }
+
+}
+
+void
+bx_ne2k_c::init(void)
+{
+  BX_DEBUG(("Init $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $"));
+
+  // Read in values from config file
+  BX_NE2K_THIS s.base_address = bx_options.ne2k.Oioaddr->get ();
+  BX_NE2K_THIS s.base_irq     = bx_options.ne2k.Oirq->get ();
+  memcpy(BX_NE2K_THIS s.physaddr, bx_options.ne2k.Omacaddr->getptr (), 6);
+
+  if (BX_NE2K_THIS s.tx_timer_index == BX_NULL_TIMER_HANDLE) {
+    BX_NE2K_THIS s.tx_timer_index =
+      bx_pc_system.register_timer(this, tx_timer_handler, 0,
+                                  0,0, "ne2k"); // one-shot, inactive
+  }
+  // Register the IRQ and i/o port addresses
+  DEV_register_irq(BX_NE2K_THIS s.base_irq, "NE2000 ethernet NIC");
+
+  for (unsigned addr = BX_NE2K_THIS s.base_address; 
+       addr <= BX_NE2K_THIS s.base_address + 0x20; 
+       addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "ne2000 NIC", 3);
+    DEV_register_iowrite_handler(this, write_handler, addr, "ne2000 NIC", 3);
+  }
+  BX_INFO(("port 0x%x/32 irq %d mac %02x:%02x:%02x:%02x:%02x:%02x",
+           BX_NE2K_THIS s.base_address,
+           BX_NE2K_THIS s.base_irq,
+           BX_NE2K_THIS s.physaddr[0],
+           BX_NE2K_THIS s.physaddr[1],
+           BX_NE2K_THIS s.physaddr[2],
+           BX_NE2K_THIS s.physaddr[3],
+           BX_NE2K_THIS s.physaddr[4],
+           BX_NE2K_THIS s.physaddr[5]));
+
+  // Initialise the mac address area by doubling the physical address
+  BX_NE2K_THIS s.macaddr[0]  = BX_NE2K_THIS s.physaddr[0];
+  BX_NE2K_THIS s.macaddr[1]  = BX_NE2K_THIS s.physaddr[0];
+  BX_NE2K_THIS s.macaddr[2]  = BX_NE2K_THIS s.physaddr[1];
+  BX_NE2K_THIS s.macaddr[3]  = BX_NE2K_THIS s.physaddr[1];
+  BX_NE2K_THIS s.macaddr[4]  = BX_NE2K_THIS s.physaddr[2];
+  BX_NE2K_THIS s.macaddr[5]  = BX_NE2K_THIS s.physaddr[2];
+  BX_NE2K_THIS s.macaddr[6]  = BX_NE2K_THIS s.physaddr[3];
+  BX_NE2K_THIS s.macaddr[7]  = BX_NE2K_THIS s.physaddr[3];
+  BX_NE2K_THIS s.macaddr[8]  = BX_NE2K_THIS s.physaddr[4];
+  BX_NE2K_THIS s.macaddr[9]  = BX_NE2K_THIS s.physaddr[4];
+  BX_NE2K_THIS s.macaddr[10] = BX_NE2K_THIS s.physaddr[5];
+  BX_NE2K_THIS s.macaddr[11] = BX_NE2K_THIS s.physaddr[5];
+    
+  // ne2k signature
+  for (int i = 12; i < 32; i++) 
+    BX_NE2K_THIS s.macaddr[i] = 0x57;
+    
+  // Attach to the simulated ethernet dev
+  char *ethmod = bx_options.ne2k.Oethmod->get_choice(bx_options.ne2k.Oethmod->get());
+  BX_NE2K_THIS ethdev = eth_locator_c::create(ethmod,
+                                              bx_options.ne2k.Oethdev->getptr (),
+                                              (const char *) bx_options.ne2k.Omacaddr->getptr (),
+                                              rx_handler, 
+                                              this);
+
+  if (BX_NE2K_THIS ethdev == NULL) {
+    BX_PANIC(("could not find eth module %s", ethmod));
+    // if they continue, use null.
+    BX_INFO(("could not find eth module %s - using null instead", ethmod));
+
+    BX_NE2K_THIS ethdev = eth_locator_c::create("null", NULL,
+                                                (const char *) bx_options.ne2k.Omacaddr->getptr (),
+                                                rx_handler, 
+                                                this);
+    if (BX_NE2K_THIS ethdev == NULL)
+      BX_PANIC(("could not locate null module"));
+  }
+
+  // Bring the register state into power-up state
+  theNE2kDevice->reset(BX_RESET_HARDWARE);
+}
+
+#if BX_DEBUGGER
+
+/*
+ * this implements the info ne2k commands in the debugger.
+ * info ne2k - shows all registers
+ * info ne2k page N - shows all registers in a page
+ * info ne2k page N reg M - shows just one register
+ */
+
+#define SHOW_FIELD(reg,field) do { \
+  if (n>0 && !(n%5)) dbg_printf ("\n  "); \
+  dbg_printf ("%s=%d ", #field, BX_NE2K_THIS s.reg.field); \
+  n++; \
+} while (0);
+#define BX_HIGH_BYTE(x) ((0xff00 & (x)) >> 8)
+#define BX_LOW_BYTE(x) (0x00ff & (x))
+#define BX_DUPLICATE(n) if (brief && num!=n) break;
+
+void
+bx_ne2k_c::print_info (FILE *fp, int page, int reg, int brief)
+{
+  int i;
+  int n = 0;
+  if (page < 0) {
+    for (page=0; page<=2; page++)
+      theNE2kDevice->print_info (fp, page, reg, 1);
+    // tell them how to use this command
+    dbg_printf ("\nHow to use the info ne2k command:\n");
+    dbg_printf ("info ne2k - show all registers\n");
+    dbg_printf ("info ne2k page N - show registers in page N\n");
+    dbg_printf ("info ne2k page N reg M - show just one register\n");
+    return;
+  }
+  if (page > 2) {
+    dbg_printf ("NE2K has only pages 0, 1, and 2.  Page %d is out of range.\n", page);
+    return;
+  }
+  if (reg < 0) {
+    dbg_printf ("NE2K registers, page %d\n", page);
+    dbg_printf ("----------------------\n");
+    for (reg=0; reg<=15; reg++)
+      theNE2kDevice->print_info (fp, page, reg, 1);
+    dbg_printf ("----------------------\n");
+    return;
+  }
+  if (reg > 15) {
+    dbg_printf ("NE2K has only registers 0-15 (0x0-0xf).  Register %d is out of range.\n", reg);
+    return;
+  }
+  if (!brief) {
+    dbg_printf ("NE2K Info - page %d, register 0x%02x\n", page, reg);
+    dbg_printf ("----------------------------------\n");
+  }
+  int num = page*0x100 + reg;
+  switch (num) {
+    case 0x0000:
+    case 0x0100:
+    case 0x0200:
+      dbg_printf ("CR (Command register):\n  ");
+      SHOW_FIELD (CR, stop);
+      SHOW_FIELD (CR, start);
+      SHOW_FIELD (CR, tx_packet);
+      SHOW_FIELD (CR, rdma_cmd);
+      SHOW_FIELD (CR, pgsel);
+      dbg_printf ("\n");
+      break;
+    case 0x0003:
+      dbg_printf ("BNRY = Boundary Pointer = 0x%02x\n", BX_NE2K_THIS s.bound_ptr);
+      break;
+    case 0x0004:
+      dbg_printf ("TSR (Transmit Status Register), read-only:\n  ");
+      SHOW_FIELD (TSR, tx_ok);
+      SHOW_FIELD (TSR, reserved);
+      SHOW_FIELD (TSR, collided);
+      SHOW_FIELD (TSR, aborted);
+      SHOW_FIELD (TSR, no_carrier);
+      SHOW_FIELD (TSR, fifo_ur);
+      SHOW_FIELD (TSR, cd_hbeat);
+      SHOW_FIELD (TSR, ow_coll);
+      dbg_printf ("\n");
+      // fall through into TPSR, no break line.
+    case 0x0204:
+      dbg_printf ("TPSR = Transmit Page Start = 0x%02x\n", BX_NE2K_THIS s.tx_page_start);
+      break;
+    case 0x0005:
+    case 0x0006:  BX_DUPLICATE(0x0005);
+      dbg_printf ("NCR = Number of Collisions Register (read-only) = 0x%02x\n", BX_NE2K_THIS s.num_coll);
+      dbg_printf ("TBCR1,TBCR0 = Transmit Byte Count = %02x %02x\n", 
+         BX_HIGH_BYTE (BX_NE2K_THIS s.tx_bytes),
+         BX_LOW_BYTE (BX_NE2K_THIS s.tx_bytes));
+      dbg_printf ("FIFO = %02x\n", BX_NE2K_THIS s.fifo);
+      break;
+    case 0x0007:
+      dbg_printf ("ISR (Interrupt Status Register):\n  ");
+      SHOW_FIELD (ISR, pkt_rx);
+      SHOW_FIELD (ISR, pkt_tx);
+      SHOW_FIELD (ISR, rx_err);
+      SHOW_FIELD (ISR, tx_err);
+      SHOW_FIELD (ISR, overwrite);
+      SHOW_FIELD (ISR, cnt_oflow);
+      SHOW_FIELD (ISR, rdma_done);
+      SHOW_FIELD (ISR, reset);
+      dbg_printf ("\n");
+      break;
+    case 0x0008:
+    case 0x0009:  BX_DUPLICATE(0x0008);
+      dbg_printf ("CRDA1,0 = Current remote DMA address = %02x %02x\n", 
+         BX_HIGH_BYTE (BX_NE2K_THIS s.remote_dma),
+         BX_LOW_BYTE (BX_NE2K_THIS s.remote_dma));
+      dbg_printf ("RSAR1,0 = Remote start address = %02x %02x\n", 
+         BX_HIGH_BYTE(s.remote_start),
+         BX_LOW_BYTE(s.remote_start));
+      break;
+    case 0x000a:
+    case 0x000b:  BX_DUPLICATE(0x000a);
+      dbg_printf ("RCBR1,0 = Remote byte count = %02x\n", BX_NE2K_THIS s.remote_bytes);
+      break;
+    case 0x000c:
+      dbg_printf ("RSR (Receive Status Register), read-only:\n  ");
+      SHOW_FIELD (RSR, rx_ok);
+      SHOW_FIELD (RSR, bad_crc);
+      SHOW_FIELD (RSR, bad_falign);
+      SHOW_FIELD (RSR, fifo_or);
+      SHOW_FIELD (RSR, rx_missed);
+      SHOW_FIELD (RSR, rx_mbit);
+      SHOW_FIELD (RSR, rx_disabled);
+      SHOW_FIELD (RSR, deferred);
+      dbg_printf ("\n");
+      // fall through into RCR
+    case 0x020c:
+      dbg_printf ("RCR (Receive Configuration Register):\n  ");
+      SHOW_FIELD (RCR, errors_ok);
+      SHOW_FIELD (RCR, runts_ok);
+      SHOW_FIELD (RCR, broadcast);
+      SHOW_FIELD (RCR, multicast);
+      SHOW_FIELD (RCR, promisc);
+      SHOW_FIELD (RCR, monitor);
+      SHOW_FIELD (RCR, reserved);
+      dbg_printf ("\n");
+      break;
+    case 0x000d:
+      dbg_printf ("CNTR0 = Tally Counter 0 (Frame alignment errors) = %02x\n",
+         BX_NE2K_THIS s.tallycnt_0);
+      // fall through into TCR
+    case 0x020d:
+      dbg_printf ("TCR (Transmit Configuration Register):\n  ");
+      SHOW_FIELD (TCR, crc_disable);
+      SHOW_FIELD (TCR, loop_cntl);
+      SHOW_FIELD (TCR, ext_stoptx);
+      SHOW_FIELD (TCR, coll_prio);
+      SHOW_FIELD (TCR, reserved);
+      dbg_printf ("\n");
+      break;
+    case 0x000e:
+      dbg_printf ("CNTR1 = Tally Counter 1 (CRC Errors) = %02x\n",
+         BX_NE2K_THIS s.tallycnt_1);
+      // fall through into DCR
+    case 0x020e:
+      dbg_printf ("DCR (Data Configuration Register):\n  ");
+      SHOW_FIELD (DCR, wdsize);
+      SHOW_FIELD (DCR, endian);
+      SHOW_FIELD (DCR, longaddr);
+      SHOW_FIELD (DCR, loop);
+      SHOW_FIELD (DCR, auto_rx);
+      SHOW_FIELD (DCR, fifo_size);
+      dbg_printf ("\n");
+      break;
+    case 0x000f:
+      dbg_printf ("CNTR2 = Tally Counter 2 (Missed Packet Errors) = %02x\n",
+         BX_NE2K_THIS s.tallycnt_2);
+      // fall through into IMR
+    case 0x020f:
+      dbg_printf ("IMR (Interrupt Mask Register)\n  ");
+      SHOW_FIELD (IMR, rx_inte);
+      SHOW_FIELD (IMR, tx_inte);
+      SHOW_FIELD (IMR, rxerr_inte);
+      SHOW_FIELD (IMR, txerr_inte);
+      SHOW_FIELD (IMR, overw_inte);
+      SHOW_FIELD (IMR, cofl_inte);
+      SHOW_FIELD (IMR, rdma_inte);
+      SHOW_FIELD (IMR, reserved);
+      dbg_printf ("\n");
+      break;
+    case 0x0101:
+    case 0x0102:  BX_DUPLICATE(0x0101);
+    case 0x0103:  BX_DUPLICATE(0x0101);
+    case 0x0104:  BX_DUPLICATE(0x0101);
+    case 0x0105:  BX_DUPLICATE(0x0101);
+    case 0x0106:  BX_DUPLICATE(0x0101);
+      dbg_printf ("MAC address registers are located at page 1, registers 1-6.\n");
+      dbg_printf ("The MAC address is ");
+      for (i=0; i<=5; i++) 
+       dbg_printf ("%02x%c", BX_NE2K_THIS s.physaddr[i], i<5?':' : '\n');
+      break;
+    case 0x0107:
+      dbg_printf ("Current page is 0x%02x\n", BX_NE2K_THIS s.curr_page);
+      break;
+    case 0x0108:
+    case 0x0109:  BX_DUPLICATE(0x0108);
+    case 0x010A:  BX_DUPLICATE(0x0108);
+    case 0x010B:  BX_DUPLICATE(0x0108);
+    case 0x010C:  BX_DUPLICATE(0x0108);
+    case 0x010D:  BX_DUPLICATE(0x0108);
+    case 0x010E:  BX_DUPLICATE(0x0108);
+    case 0x010F:  BX_DUPLICATE(0x0108);
+      dbg_printf ("MAR0-7 (Multicast address registers 0-7) are set to:\n");
+      for (i=0; i<8; i++) dbg_printf ("%02x ", BX_NE2K_THIS s.mchash[i]);
+      dbg_printf ("\nMAR0 is listed first.\n");
+      break;
+    case 0x0001:
+    case 0x0002:  BX_DUPLICATE(0x0001);
+    case 0x0201:  BX_DUPLICATE(0x0001);
+    case 0x0202:  BX_DUPLICATE(0x0001);
+      dbg_printf ("PSTART = Page start register = %02x\n", BX_NE2K_THIS s.page_start);
+      dbg_printf ("PSTOP = Page stop register = %02x\n", BX_NE2K_THIS s.page_stop);
+      dbg_printf ("Local DMA address = %02x %02x\n", 
+         BX_HIGH_BYTE(BX_NE2K_THIS s.local_dma),
+         BX_LOW_BYTE(BX_NE2K_THIS s.local_dma));
+      break;
+    case 0x0203:
+      dbg_printf ("Remote Next Packet Pointer = %02x\n", BX_NE2K_THIS s.rempkt_ptr);
+      break;
+    case 0x0205:
+      dbg_printf ("Local Next Packet Pointer = %02x\n", BX_NE2K_THIS s.localpkt_ptr);
+      break;
+    case 0x0206:
+    case 0x0207:  BX_DUPLICATE(0x0206);
+      dbg_printf ("Address Counter= %02x %02x\n", 
+        BX_HIGH_BYTE(BX_NE2K_THIS s.address_cnt),
+        BX_LOW_BYTE(BX_NE2K_THIS s.address_cnt));
+      break;
+    case 0x0208:
+    case 0x0209:  BX_DUPLICATE(0x0208);
+    case 0x020A:  BX_DUPLICATE(0x0208);
+    case 0x020B:  BX_DUPLICATE(0x0208);
+      if (!brief) dbg_printf ("Reserved\n");
+    case 0xffff:
+      dbg_printf ("IMR (Interrupt Mask Register):\n  ");
+      dbg_printf ("\n");
+      break;
+    default:
+      dbg_printf ("NE2K info: sorry, page %d register %d cannot be displayed.\n", page, reg);
+  }
+  if (!brief)
+    dbg_printf ("\n");
+}
+
+#else
+
+void
+bx_ne2k_c::print_info (FILE *fp, int page, int reg, int brief)
+{
+}
+
+#endif
+
+#endif /* if BX_NE2K_SUPPORT */
diff --git a/tools/ioemu/iodev/ne2k.h b/tools/ioemu/iodev/ne2k.h
new file mode 100644 (file)
index 0000000..37cc712
--- /dev/null
@@ -0,0 +1,239 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: ne2k.h,v 1.11 2003/03/02 23:59:11 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Peter Grehan (grehan@iprg.nokia.com) coded all of this
+// NE2000/ether stuff.
+
+//
+// An implementation of an ne2000 ISA ethernet adapter. This part uses
+// a National Semiconductor DS-8390 ethernet MAC chip, with some h/w
+// to provide a windowed memory region for the chip and a MAC address.
+//
+
+
+#if BX_USE_NE2K_SMF
+#  define BX_NE2K_SMF  static
+#  define BX_NE2K_THIS theNE2kDevice->
+#else
+#  define BX_NE2K_SMF
+#  define BX_NE2K_THIS this->
+#endif
+
+#define  BX_NE2K_MEMSIZ    (32*1024)
+#define  BX_NE2K_MEMSTART  (16*1024)
+#define  BX_NE2K_MEMEND    (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
+
+typedef struct {
+    //
+    // ne2k register state
+   
+    //
+    // Page 0
+    //
+    //  Command Register - 00h read/write
+    struct {
+        bx_bool  stop;         // STP - Software Reset command
+        bx_bool  start;                // START - start the NIC
+        bx_bool  tx_packet;    // TXP - initiate packet transmission
+        Bit8u    rdma_cmd;      // RD0,RD1,RD2 - Remote DMA command
+       Bit8u    pgsel;         // PS0,PS1 - Page select
+    } CR;
+    // Interrupt Status Register - 07h read/write
+    struct {  
+       bx_bool  pkt_rx;        // PRX - packet received with no errors
+       bx_bool  pkt_tx;        // PTX - packet transmitted with no errors
+       bx_bool  rx_err;        // RXE - packet received with 1 or more errors
+       bx_bool  tx_err;        // TXE - packet tx'd       "  " "    "    "
+       bx_bool  overwrite;     // OVW - rx buffer resources exhausted
+       bx_bool  cnt_oflow;     // CNT - network tally counter MSB's set
+       bx_bool  rdma_done;     // RDC - remote DMA complete
+       bx_bool  reset;         // RST - reset status
+    } ISR;
+    // Interrupt Mask Register - 0fh write
+    struct {
+       bx_bool  rx_inte;       // PRXE - packet rx interrupt enable
+       bx_bool  tx_inte;       // PTXE - packet tx interrput enable
+       bx_bool  rxerr_inte;    // RXEE - rx error interrupt enable
+       bx_bool  txerr_inte;    // TXEE - tx error interrupt enable
+       bx_bool  overw_inte;    // OVWE - overwrite warn int enable
+       bx_bool  cofl_inte;     // CNTE - counter o'flow int enable
+       bx_bool  rdma_inte;     // RDCE - remote DMA complete int enable
+       bx_bool  reserved;      //  D7 - reserved
+    } IMR;
+    // Data Configuration Register - 0eh write
+    struct {
+       bx_bool  wdsize;        // WTS - 8/16-bit select
+       bx_bool  endian;        // BOS - byte-order select
+       bx_bool  longaddr;      // LAS - long-address select
+       bx_bool  loop;          // LS  - loopback select
+       bx_bool  auto_rx;       // AR  - auto-remove rx packets with remote DMA
+        Bit8u    fifo_size;    // FT0,FT1 - fifo threshold
+    } DCR;
+    // Transmit Configuration Register - 0dh write
+    struct {
+       bx_bool  crc_disable;   // CRC - inhibit tx CRC
+       Bit8u    loop_cntl;     // LB0,LB1 - loopback control
+       bx_bool  ext_stoptx;    // ATD - allow tx disable by external mcast
+       bx_bool  coll_prio;     // OFST - backoff algorithm select
+       Bit8u    reserved;      //  D5,D6,D7 - reserved
+    } TCR;
+    // Transmit Status Register - 04h read
+    struct {
+       bx_bool  tx_ok;         // PTX - tx complete without error
+       bx_bool  reserved;      //  D1 - reserved
+       bx_bool  collided;      // COL - tx collided >= 1 times
+       bx_bool  aborted;       // ABT - aborted due to excessive collisions
+       bx_bool  no_carrier;    // CRS - carrier-sense lost
+       bx_bool  fifo_ur;       // FU  - FIFO underrun
+       bx_bool  cd_hbeat;      // CDH - no tx cd-heartbeat from transceiver
+       bx_bool  ow_coll;       // OWC - out-of-window collision
+    } TSR;
+    // Receive Configuration Register - 0ch write
+    struct {
+       bx_bool  errors_ok;     // SEP - accept pkts with rx errors
+       bx_bool  runts_ok;      // AR  - accept < 64-byte runts
+       bx_bool  broadcast;     // AB  - accept eth broadcast address
+       bx_bool  multicast;     // AM  - check mcast hash array
+       bx_bool  promisc;       // PRO - accept all packets
+       bx_bool  monitor;       // MON - check pkts, but don't rx
+       Bit8u    reserved;      //  D6,D7 - reserved
+    } RCR;
+    // Receive Status Register - 0ch read
+    struct {
+       bx_bool  rx_ok;         // PRX - rx complete without error
+       bx_bool  bad_crc;       // CRC - Bad CRC detected
+       bx_bool  bad_falign;    // FAE - frame alignment error
+       bx_bool  fifo_or;       // FO  - FIFO overrun
+       bx_bool  rx_missed;     // MPA - missed packet error
+       bx_bool  rx_mbit;       // PHY - unicast or mcast/bcast address match
+       bx_bool  rx_disabled;   // DIS - set when in monitor mode
+       bx_bool  deferred;      // DFR - collision active
+    } RSR;
+
+    Bit16u local_dma;  // 01,02h read ; current local DMA addr
+    Bit8u  page_start;  // 01h write ; page start register
+    Bit8u  page_stop;   // 02h write ; page stop register
+    Bit8u  bound_ptr;   // 03h read/write ; boundary pointer
+    Bit8u  tx_page_start; // 04h write ; transmit page start register
+    Bit8u  num_coll;    // 05h read  ; number-of-collisions register
+    Bit16u tx_bytes;    // 05,06h write ; transmit byte-count register
+    Bit8u  fifo;       // 06h read  ; FIFO
+    Bit16u remote_dma;  // 08,09h read ; current remote DMA addr
+    Bit16u remote_start;  // 08,09h write ; remote start address register
+    Bit16u remote_bytes;  // 0a,0bh write ; remote byte-count register
+    Bit8u  tallycnt_0;  // 0dh read  ; tally counter 0 (frame align errors)
+    Bit8u  tallycnt_1;  // 0eh read  ; tally counter 1 (CRC errors)
+    Bit8u  tallycnt_2;  // 0fh read  ; tally counter 2 (missed pkt errors)
+
+    //
+    // Page 1
+    //
+    //   Command Register 00h (repeated)
+    //
+    Bit8u  physaddr[6];  // 01-06h read/write ; MAC address
+    Bit8u  curr_page;    // 07h read/write ; current page register
+    Bit8u  mchash[8];    // 08-0fh read/write ; multicast hash array
+
+    //
+    // Page 2  - diagnostic use only
+    // 
+    //   Command Register 00h (repeated)
+    //
+    //   Page Start Register 01h read  (repeated)
+    //   Page Stop Register  02h read  (repeated)
+    //   Current Local DMA Address 01,02h write (repeated)
+    //   Transmit Page start address 04h read (repeated)
+    //   Receive Configuration Register 0ch read (repeated)
+    //   Transmit Configuration Register 0dh read (repeated)
+    //   Data Configuration Register 0eh read (repeated)
+    //   Interrupt Mask Register 0fh read (repeated)
+    //
+    Bit8u  rempkt_ptr;   // 03h read/write ; remote next-packet pointer
+    Bit8u  localpkt_ptr; // 05h read/write ; local next-packet pointer
+    Bit16u address_cnt;  // 06,07h read/write ; address counter
+
+    //
+    // Page 3  - should never be modified.
+    //
+
+    // Novell ASIC state
+    Bit8u  macaddr[32];          // ASIC ROM'd MAC address, even bytes
+    Bit8u  mem[BX_NE2K_MEMSIZ];  // on-chip packet memory
+
+    // ne2k internal state
+    Bit32u base_address;
+    int    base_irq;
+    int    tx_timer_index;
+    int    tx_timer_active;
+
+} bx_ne2k_t;
+
+
+
+class bx_ne2k_c : public bx_ne2k_stub_c {
+public:
+  bx_ne2k_c(void);
+  ~bx_ne2k_c(void);
+  virtual void init(void);
+  virtual void reset(unsigned type);
+  virtual void print_info (FILE *file, int page, int reg, int nodups);
+
+private:
+  bx_ne2k_t s;
+
+  eth_pktmover_c *ethdev;
+
+  BX_NE2K_SMF Bit32u read_cr(void);
+  BX_NE2K_SMF void   write_cr(Bit32u value);
+
+  BX_NE2K_SMF Bit32u chipmem_read(Bit32u address, unsigned io_len) BX_CPP_AttrRegparmN(2);
+  BX_NE2K_SMF Bit32u asic_read(Bit32u offset, unsigned io_len) BX_CPP_AttrRegparmN(2);
+  BX_NE2K_SMF Bit32u page0_read(Bit32u offset, unsigned io_len);
+  BX_NE2K_SMF Bit32u page1_read(Bit32u offset, unsigned io_len);
+  BX_NE2K_SMF Bit32u page2_read(Bit32u offset, unsigned io_len);
+  BX_NE2K_SMF Bit32u page3_read(Bit32u offset, unsigned io_len);
+
+  BX_NE2K_SMF void chipmem_write(Bit32u address, Bit32u value, unsigned io_len) BX_CPP_AttrRegparmN(3);
+  BX_NE2K_SMF void asic_write(Bit32u address, Bit32u value, unsigned io_len);
+  BX_NE2K_SMF void page0_write(Bit32u address, Bit32u value, unsigned io_len);
+  BX_NE2K_SMF void page1_write(Bit32u address, Bit32u value, unsigned io_len);
+  BX_NE2K_SMF void page2_write(Bit32u address, Bit32u value, unsigned io_len);
+  BX_NE2K_SMF void page3_write(Bit32u address, Bit32u value, unsigned io_len);
+
+  static void tx_timer_handler(void *);
+  BX_NE2K_SMF void tx_timer(void);
+
+  static void rx_handler(void *arg, const void *buf, unsigned len);
+  BX_NE2K_SMF unsigned mcast_index(const void *dst);
+  BX_NE2K_SMF void rx_frame(const void *buf, unsigned io_len);
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_NE2K_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+};
diff --git a/tools/ioemu/iodev/osdep.cc b/tools/ioemu/iodev/osdep.cc
new file mode 100644 (file)
index 0000000..c010306
--- /dev/null
@@ -0,0 +1,340 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: osdep.cc,v 1.14.2.1 2004/02/06 22:14:34 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// osdep.cc
+// 
+// Provide definition of library functions that are missing on various
+// systems.  The only reason this is a .cc file rather than a .c file
+// is so that it can include bochs.h.  Bochs.h includes all the required
+// system headers, with appropriate #ifdefs for different compilers and 
+// platforms.
+//
+
+#include "bochs.h"
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions.  These should work on any platform 
+// that needs them.
+//////////////////////////////////////////////////////////////////////
+
+#if !BX_HAVE_SNPRINTF
+/* XXX use real snprintf */
+/* if they don't have snprintf, just use sprintf */
+int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
+{
+  va_list arg;
+  int done;
+
+  va_start (arg, format);
+  done = vsprintf (s, format, arg);
+  va_end (arg);
+
+  return done;
+}
+#endif  /* !BX_HAVE_SNPRINTF */
+
+
+#if (!BX_HAVE_STRTOULL && !BX_HAVE_STRTOUQ)
+/* taken from glibc-2.2.2: strtod.c, and stripped down a lot.  There are 
+   still a few leftover references to decimal points and exponents, 
+   but it works for bases 10 and 16 */
+
+#define RETURN(val,end)                                                              \
+    do { if (endptr != NULL) *endptr = (char *) (end);               \
+        return val; } while (0)
+
+Bit64u
+bx_strtoull (const char *nptr, char **endptr, int baseignore)
+{
+  int negative;                        /* The sign of the number.  */
+  int exponent;                        /* Exponent of the number.  */
+
+  /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
+  int base = 10;
+
+  /* Number of bits currently in result value.  */
+  int bits;
+
+  /* Running pointer after the last character processed in the string.  */
+  const char *cp, *tp;
+  /* Start of significant part of the number.  */
+  const char *startp, *start_of_digits;
+  /* Total number of digit and number of digits in integer part.  */
+  int dig_no;
+  /* Contains the last character read.  */
+  char c;
+
+  Bit64s n = 0;
+  char const *p;
+
+  /* Prepare number representation.  */
+  exponent = 0;
+  negative = 0;
+  bits = 0;
+
+  /* Parse string to get maximal legal prefix.  We need the number of
+     characters of the integer part, the fractional part and the exponent.  */
+  cp = nptr - 1;
+  /* Ignore leading white space.  */
+  do
+    c = *++cp;
+  while (isspace (c));
+
+  /* Get sign of the result.  */
+  if (c == '-')
+    {
+      negative = 1;
+      c = *++cp;
+    }
+  else if (c == '+')
+    c = *++cp;
+
+  if (c < '0' || c > '9')
+    {
+      /* It is really a text we do not recognize.  */
+      RETURN (0, nptr);
+    }
+
+  /* First look whether we are faced with a hexadecimal number.  */
+  if (c == '0' && tolower (cp[1]) == 'x')
+    {
+      /* Okay, it is a hexa-decimal number.  Remember this and skip
+        the characters.  BTW: hexadecimal numbers must not be
+        grouped.  */
+      base = 16;
+      cp += 2;
+      c = *cp;
+    }
+
+  /* Record the start of the digits, in case we will check their grouping.  */
+  start_of_digits = startp = cp;
+
+  /* Ignore leading zeroes.  This helps us to avoid useless computations.  */
+  while (c == '0')
+    c = *++cp;
+
+  /* If no other digit but a '0' is found the result is 0.0.
+     Return current read pointer.  */
+  if ((c < '0' || c > '9')
+      && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
+      && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
+      && (base != 16 && tolower (c) != 'e'))
+    {
+      tp = start_of_digits;
+      /* If TP is at the start of the digits, there was no correctly
+        grouped prefix of the string; so no number found.  */
+      RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
+    }
+
+  /* Remember first significant digit and read following characters until the
+     decimal point, exponent character or any non-FP number character.  */
+  startp = cp;
+  dig_no = 0;
+  while (1)
+    {
+      if ((c >= '0' && c <= '9')
+         || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
+       ++dig_no;
+      else
+       break;
+      c = *++cp;
+    }
+
+  /* The whole string is parsed.  Store the address of the next character.  */
+  if (endptr)
+    *endptr = (char *) cp;
+
+  if (dig_no == 0) 
+    return 0;
+
+  for (p=start_of_digits; p!=cp; p++) {
+    n = n * (Bit64s)base;
+    c = tolower (*p);
+    c = (c >= 'a') ? (10+c-'a') : c-'0';
+    n = n + (Bit64s)c;
+    //printf ("after shifting in digit %c, n is %lld\n", *p, n);
+  }
+  return negative? -n : n;
+}
+#endif  /* !BX_HAVE_STRTOULL */
+
+#if BX_TEST_STRTOULL_MAIN
+/* test driver for strtoull.  Do not compile by default. */
+int main (int argc, char **argv)
+{
+  char buf[256], *endbuf;
+  long l;
+  Bit64s ll;
+  while (1) {
+    printf ("Enter a long int: ");
+    gets (buf);
+    l = strtoul (buf, &endbuf, 10);
+    printf ("As a long, %ld\n", l);
+    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
+    ll = bx_strtoull (buf, &endbuf, 10);
+    printf ("As a long long, %lld\n", ll);
+    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
+  }
+  return 0;
+}
+#endif  /* BX_TEST_STRTOULL_MAIN */
+
+#if !BX_HAVE_STRDUP
+/* XXX use real strdup */
+char *bx_strdup(const char *str)
+{
+       char *temp;
+       
+       temp = (char*)malloc(strlen(str)+1);
+       sprintf(temp, "%s", str);
+       return temp;
+       
+       // Well, I'm sure this isn't how strdup is REALLY implemented,
+       // but it works...
+}
+#endif  /* !BX_HAVE_STRDUP */
+
+#if !BX_HAVE_STRREV
+char *bx_strrev(char *str)
+{
+  char *p1, *p2;
+
+  if (! str || ! *str)
+    return str;
+
+  for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
+    *p1 ^= *p2;
+    *p2 ^= *p1;
+    *p1 ^= *p2;
+  }
+  return str;
+}
+#endif  /* !BX_HAVE_STRREV */
+
+#if BX_WITH_MACOS
+namespace std{extern "C" {char *mktemp(char *tpl);}}
+#endif
+#if !BX_HAVE_MKSTEMP
+int bx_mkstemp(char *tpl)
+{
+  mktemp(tpl);
+  return ::open(tpl, O_RDWR | O_CREAT | O_TRUNC
+#  ifdef O_BINARY
+            | O_BINARY
+#  endif
+              , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
+}
+#endif // !BX_HAVE_MKSTEMP
+
+//////////////////////////////////////////////////////////////////////
+// Missing library functions, implemented for MacOS only
+//////////////////////////////////////////////////////////////////////
+
+#if BX_WITH_MACOS
+// these functions are part of MacBochs.  They are not intended to be
+// portable!
+#include <Devices.h>
+#include <Files.h>
+#include <Disks.h>
+
+int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
+{
+       OSErr err;
+       IOParam param;
+       
+       param.ioRefNum=-5; // Refnum of the floppy disk driver
+       param.ioVRefNum=1;
+       param.ioPosMode=fsFromStart;
+       param.ioPosOffset=offset;
+       param.ioBuffer=buffer;
+       param.ioReqCount=bytes;
+       err = PBReadSync((union ParamBlockRec *)(&param));
+       return param.ioActCount;
+}
+
+int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
+{
+       OSErr           err;
+       IOParam param;
+       
+       param.ioRefNum=-5; // Refnum of the floppy disk driver
+       param.ioVRefNum=1;
+       param.ioPosMode=fsFromStart;
+       param.ioPosOffset=offset;
+       param.ioBuffer=buffer;
+       param.ioReqCount=bytes;
+       err = PBWriteSync((union ParamBlockRec *)(&param));
+       return param.ioActCount;
+}
+
+int fd_stat(struct stat *buf)
+{
+       OSErr           err;
+       DrvSts  status;
+       int                     result;
+       
+       result = 0;
+       err = DriveStatus(1, &status);
+       if (status.diskInPlace <1 || status.diskInPlace > 2)
+               result = -1;
+       buf->st_mode = S_IFCHR;
+       return result;
+}
+#endif /* BX_WITH_MACOS */
+
+
+
+//////////////////////////////////////////////////////////////////////
+// New functions to replace library functions
+//   with OS-independent versions
+//////////////////////////////////////////////////////////////////////
+
+#if BX_HAVE_REALTIME_USEC
+#  if BX_HAVE_GETTIMEOFDAY
+Bit64u bx_get_realtime64_usec (void) {
+  timeval thetime;
+  gettimeofday(&thetime,0);
+  Bit64u mytime;
+  mytime=(Bit64u)thetime.tv_sec*(Bit64u)1000000+(Bit64u)thetime.tv_usec;
+  return mytime;
+}
+#  elif defined(WIN32)
+Bit64u last_realtime64_top = 0;
+Bit64u last_realtime64_bottom = 0;
+Bit64u bx_get_realtime64_usec (void) {
+  Bit64u new_bottom = ((Bit64u) GetTickCount()) & BX_CONST64(0x0FFFFFFFF);
+  if(new_bottom < last_realtime64_bottom) {
+    last_realtime64_top += BX_CONST64(0x0000000100000000);
+  }
+  last_realtime64_bottom = new_bottom;
+  Bit64u interim_realtime64 =
+    (last_realtime64_top & BX_CONST64(0xFFFFFFFF00000000)) |
+    (new_bottom          & BX_CONST64(0x00000000FFFFFFFF));
+  return interim_realtime64*(BX_CONST64(1000));
+}
+#  endif
+#endif
diff --git a/tools/ioemu/iodev/parallel.cc b/tools/ioemu/iodev/parallel.cc
new file mode 100644 (file)
index 0000000..8b0d4b3
--- /dev/null
@@ -0,0 +1,300 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: parallel.cc,v 1.24 2003/10/29 17:29:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+////////////////////////////////////////////////////////
+// This code was just a few stubs until Volker.Ruppert@t-online.de 
+// fixed it up in November 2001.
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#define LOG_THIS theParallelDevice->
+
+bx_parallel_c *theParallelDevice = NULL;
+
+  int
+libparallel_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theParallelDevice = new bx_parallel_c ();
+  bx_devices.pluginParallelDevice = theParallelDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theParallelDevice, BX_PLUGIN_PARALLEL);
+  return(0); // Success
+}
+
+  void
+libparallel_LTX_plugin_fini(void)
+{
+}
+
+bx_parallel_c::bx_parallel_c(void)
+{
+  put("PAR");
+  settype(PARLOG);
+  s.output = NULL;
+}
+
+bx_parallel_c::~bx_parallel_c(void)
+{
+  if (s.output != NULL)
+    fclose(s.output);
+}
+
+  void
+bx_parallel_c::init(void)
+{
+  BX_DEBUG(("Init $Id: parallel.cc,v 1.24 2003/10/29 17:29:26 vruppert Exp $"));
+
+  if (bx_options.par[0].Oenabled->get ()) {
+
+    /* PARALLEL PORT 1 */
+
+    DEV_register_irq(7, "Parallel Port 1");
+    BX_INFO (("parallel port 1 at 0x378 irq 7"));
+    for (unsigned addr=0x0378; addr<=0x037A; addr++) {
+      DEV_register_ioread_handler(this, read_handler, addr, "Parallel Port 1", 1);
+      }
+    DEV_register_iowrite_handler(this, write_handler, 0x0378, "Parallel Port 1", 1);
+    DEV_register_iowrite_handler(this, write_handler, 0x037A, "Parallel Port 1", 1);
+
+    BX_PAR_THIS s.STATUS.error = 1;
+    BX_PAR_THIS s.STATUS.slct  = 1;
+    BX_PAR_THIS s.STATUS.pe    = 0;
+    BX_PAR_THIS s.STATUS.ack   = 1;
+    BX_PAR_THIS s.STATUS.busy  = 1;
+
+    BX_PAR_THIS s.CONTROL.strobe   = 0;
+    BX_PAR_THIS s.CONTROL.autofeed = 0;
+    BX_PAR_THIS s.CONTROL.init     = 1;
+    BX_PAR_THIS s.CONTROL.slct_in  = 1;
+    BX_PAR_THIS s.CONTROL.irq      = 0;
+    BX_PAR_THIS s.CONTROL.input    = 0;
+
+    BX_PAR_THIS s.initmode = 0;
+
+    if (strlen(bx_options.par[0].Ooutfile->getptr ()) > 0) {
+      s.output = fopen(bx_options.par[0].Ooutfile->getptr (), "wb");
+      if (!s.output)
+        BX_PANIC (("Could not open '%s' to write parport1 output",
+                   bx_options.par[0].Ooutfile->getptr ()));
+    }
+  }
+}
+
+  void
+bx_parallel_c::reset(unsigned type)
+{
+}
+
+  void
+bx_parallel_c::virtual_printer(void)
+{
+  if (BX_PAR_THIS s.STATUS.slct) {
+    if (BX_PAR_THIS s.output != NULL) {
+      fputc(BX_PAR_THIS s.data, BX_PAR_THIS s.output);
+      fflush (BX_PAR_THIS s.output);
+      }
+    if (BX_PAR_THIS s.CONTROL.irq == 1) {
+      DEV_pic_raise_irq(7);
+      }
+    BX_PAR_THIS s.STATUS.ack = 0;
+    BX_PAR_THIS s.STATUS.busy = 1;
+    }
+  else {
+    BX_ERROR(("data is valid, but printer is offline"));
+    }
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_parallel_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PAR_SMF
+  bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_parallel_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PAR_SMF
+
+  Bit32u retval;
+
+  switch (address) {
+    /* PARALLEL PORT 1 */
+    case 0x0378:
+      if (!BX_PAR_THIS s.CONTROL.input) {
+        return (Bit32u)BX_PAR_THIS s.data;
+      } else {
+        BX_ERROR(("read: input mode not supported"));
+        return (0xFF);
+      }
+      break;
+    case 0x0379:
+      {
+        retval = ((BX_PAR_THIS s.STATUS.busy  << 7) |
+                  (BX_PAR_THIS s.STATUS.ack   << 6) |
+                  (BX_PAR_THIS s.STATUS.pe    << 5) |
+                  (BX_PAR_THIS s.STATUS.slct  << 4) |
+                  (BX_PAR_THIS s.STATUS.error << 3));
+        if (BX_PAR_THIS s.STATUS.ack == 0) {
+          BX_PAR_THIS s.STATUS.ack = 1;
+          if (BX_PAR_THIS s.CONTROL.irq == 1) {
+            DEV_pic_lower_irq(7);
+          }
+        }
+        if (BX_PAR_THIS s.initmode == 1) {
+          BX_PAR_THIS s.STATUS.busy  = 1;
+          BX_PAR_THIS s.STATUS.slct  = 1;
+          BX_PAR_THIS s.STATUS.ack  = 0;
+          if (BX_PAR_THIS s.CONTROL.irq == 1) {
+            DEV_pic_raise_irq(7);
+          }
+          BX_PAR_THIS s.initmode = 0;
+        }
+        BX_DEBUG(("read: status register returns 0x%02x", retval));
+        return retval;
+      }
+      break;
+    case 0x037A:
+      {
+        retval = ((BX_PAR_THIS s.CONTROL.input    << 5) |
+                  (BX_PAR_THIS s.CONTROL.irq      << 4) |
+                  (BX_PAR_THIS s.CONTROL.slct_in  << 3) |
+                  (BX_PAR_THIS s.CONTROL.init     << 2) |
+                  (BX_PAR_THIS s.CONTROL.autofeed << 1) |
+                  (BX_PAR_THIS s.CONTROL.strobe));
+        BX_DEBUG(("read: control register returns 0x%02x", retval));
+        return retval;
+      }
+      break;
+  }
+  return(0);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_parallel_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PAR_SMF
+  bx_parallel_c *class_ptr = (bx_parallel_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_parallel_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PAR_SMF
+
+  switch (address) {
+    /* PARALLEL PORT 1 */
+    case 0x0378:
+      BX_PAR_THIS s.data = (Bit8u)value;
+      BX_DEBUG(("write: data output register = 0x%02x", (Bit8u)value));
+      break;
+    case 0x037A:
+      {
+        if ((value & 0x01) == 0x01) {
+          if (BX_PAR_THIS s.CONTROL.strobe == 0) {
+            BX_PAR_THIS s.CONTROL.strobe = 1;
+            virtual_printer(); // data is valid now
+          }
+        } else {
+          if (BX_PAR_THIS s.CONTROL.strobe == 1) {
+            BX_PAR_THIS s.CONTROL.strobe = 0;
+          }
+        }
+        BX_PAR_THIS s.CONTROL.autofeed = ((value & 0x02) == 0x02);
+        if ((value & 0x04) == 0x04) {
+          if (BX_PAR_THIS s.CONTROL.init == 0) {
+            BX_PAR_THIS s.CONTROL.init = 1;
+            BX_PAR_THIS s.STATUS.busy  = 0;
+            BX_PAR_THIS s.STATUS.slct  = 0;
+            BX_PAR_THIS s.initmode = 1;
+            BX_DEBUG(("printer init requested"));
+          }
+        } else {
+          if (BX_PAR_THIS s.CONTROL.init == 1) {
+            BX_PAR_THIS s.CONTROL.init = 0;
+          }
+        }
+        if ((value & 0x08) == 0x08) {
+          if (BX_PAR_THIS s.CONTROL.slct_in == 0) {
+            BX_PAR_THIS s.CONTROL.slct_in = 1;
+            BX_DEBUG(("printer now online"));
+          }
+        } else {
+          if (BX_PAR_THIS s.CONTROL.slct_in == 1) {
+            BX_PAR_THIS s.CONTROL.slct_in = 0;
+            BX_DEBUG(("printer now offline"));
+          }
+        }
+        BX_PAR_THIS s.STATUS.slct = BX_PAR_THIS s.CONTROL.slct_in;
+        if ((value & 0x10) == 0x10) {
+          if (BX_PAR_THIS s.CONTROL.irq == 0) {
+            BX_PAR_THIS s.CONTROL.irq = 1;
+            BX_DEBUG(("irq mode selected"));
+          }
+        } else {
+          if (BX_PAR_THIS s.CONTROL.irq == 1) {
+            BX_PAR_THIS s.CONTROL.irq = 0;
+            BX_DEBUG(("polling mode selected"));
+          }
+        }
+        if ((value & 0x20) == 0x20) {
+          if (BX_PAR_THIS s.CONTROL.input == 0) {
+            BX_PAR_THIS s.CONTROL.input = 1;
+            BX_DEBUG(("data input mode selected"));
+          }
+        } else {
+          if (BX_PAR_THIS s.CONTROL.input == 1) {
+            BX_PAR_THIS s.CONTROL.input = 0;
+            BX_DEBUG(("data output mode selected"));
+          }
+        }
+        if ((value & 0xC0) > 0) {
+          BX_ERROR(("write: unsupported control bit ignored"));
+        }
+      }
+      break;
+  }
+}
diff --git a/tools/ioemu/iodev/parallel.h b/tools/ioemu/iodev/parallel.h
new file mode 100644 (file)
index 0000000..b4a256a
--- /dev/null
@@ -0,0 +1,78 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: parallel.h,v 1.11 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#if BX_USE_PAR_SMF
+#  define BX_PAR_SMF  static
+#  define BX_PAR_THIS theParallelDevice->
+#else
+#  define BX_PAR_SMF
+#  define BX_PAR_THIS this->
+#endif
+
+typedef struct {
+  Bit8u data;
+  struct {
+    bx_bool error;
+    bx_bool slct;
+    bx_bool pe;
+    bx_bool ack;
+    bx_bool busy;
+  } STATUS;
+  struct {
+    bx_bool strobe;
+    bx_bool autofeed;
+    bx_bool init;
+    bx_bool slct_in;
+    bx_bool irq;
+    bx_bool input;
+  } CONTROL;
+  FILE *output;
+  bx_bool initmode;
+} bx_par_t;
+
+
+
+class bx_parallel_c : public bx_devmodel_c {
+public:
+
+  bx_parallel_c(void);
+  ~bx_parallel_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+  bx_par_t s;
+
+  static void   virtual_printer();
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PAR_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+  };
diff --git a/tools/ioemu/iodev/pc_system.cc b/tools/ioemu/iodev/pc_system.cc
new file mode 100644 (file)
index 0000000..1b58fe7
--- /dev/null
@@ -0,0 +1,556 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pc_system.cc,v 1.34 2003/06/07 19:16:51 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#include "bochs.h"
+#define LOG_THIS bx_pc_system.
+
+#ifdef WIN32
+#ifndef __MINGW32__
+// #include <winsock2.h> // +++
+#include <winsock.h>
+#endif
+#endif
+
+#if BX_SHOW_IPS
+unsigned long ips_count=0;
+#endif
+
+#if defined(PROVIDE_M_IPS)
+double     m_ips; // Millions of Instructions Per Second
+#endif
+
+// Option for turning off BX_TIMER_DEBUG?
+// Check out m_ips and ips
+
+#define SpewPeriodicTimerInfo 0
+#define MinAllowableTimerPeriod 1
+
+
+#if SpewPeriodicTimerInfo
+// If debugging, set the heartbeat to 5M cycles.  Each heartbeat
+// spews the active timer info.
+const Bit64u bx_pc_system_c::NullTimerInterval = 5000000;
+#else
+// This must be the maximum 32-bit unsigned int value, NOT (Bit64u) -1.
+const Bit64u bx_pc_system_c::NullTimerInterval = 0xffffffff;
+#endif
+
+  // constructor
+bx_pc_system_c::bx_pc_system_c(void)
+{
+  this->put("SYS");
+
+  // Timer[0] is the null timer.  It is initialized as a special
+  // case here.  It should never be turned off or modified, and its
+  // duration should always remain the same.
+  ticksTotal = 0; // Reset ticks since emulator started.
+  timer[0].period     = NullTimerInterval;
+  timer[0].timeToFire = ticksTotal + NullTimerInterval;
+  timer[0].active     = 1;
+  timer[0].continuous = 1;
+  timer[0].funct      = nullTimer;
+  timer[0].this_ptr   = this;
+  currCountdown       = NullTimerInterval;
+  currCountdownPeriod = NullTimerInterval;
+  numTimers = 1; // So far, only the nullTimer.
+  lastTimeUsec = 0;
+  usecSinceLast = 0;
+}
+
+  void
+bx_pc_system_c::init_ips(Bit32u ips)
+{
+  HRQ = 0;
+
+  enable_a20 = 1;
+  //set_INTR (0);
+
+#if BX_CPU_LEVEL < 2
+  a20_mask   =    0xfffff;
+#elif BX_CPU_LEVEL == 2
+  a20_mask   =   0xffffff;
+#else /* 386+ */
+  a20_mask   = 0xffffffff;
+#endif
+
+  // parameter 'ips' is the processor speed in Instructions-Per-Second
+  m_ips = double(ips) / 1000000.0L;
+
+  BX_DEBUG(("ips = %u", (unsigned) ips));
+}
+
+  void
+bx_pc_system_c::set_HRQ(bx_bool val)
+{
+  HRQ = val;
+  if (val)
+    BX_CPU(0)->async_event = 1;
+}
+
+
+#if (BX_NUM_SIMULATORS < 2)
+  void
+bx_pc_system_c::set_INTR(bx_bool value)
+{
+  if (bx_dbg.interrupts)
+    BX_INFO(("pc_system: Setting INTR=%d on bootstrap processor %d", (int)value, BX_BOOTSTRAP_PROCESSOR));
+  //INTR = value;
+  BX_CPU(BX_BOOTSTRAP_PROCESSOR)->set_INTR(value);
+}
+#endif
+
+//
+// Read from the IO memory address space
+//
+
+  Bit32u BX_CPP_AttrRegparmN(2)
+bx_pc_system_c::inp(Bit16u addr, unsigned io_len)
+{
+  Bit32u ret;
+
+  ret = bx_devices.inp(addr, io_len);
+
+  return( ret );
+}
+
+
+//
+// Write to the IO memory address space.
+//
+
+  void BX_CPP_AttrRegparmN(3)
+bx_pc_system_c::outp(Bit16u addr, Bit32u value, unsigned io_len)
+{
+  bx_devices.outp(addr, value, io_len);
+}
+
+  void BX_CPP_AttrRegparmN(1)
+bx_pc_system_c::set_enable_a20(Bit8u value)
+{
+#if BX_CPU_LEVEL < 2
+    BX_PANIC(("set_enable_a20() called: 8086 emulation"));
+#else
+
+#if BX_SUPPORT_A20
+  unsigned old_enable_a20 = enable_a20;
+
+  if (value) {
+    enable_a20 = 1;
+#if BX_CPU_LEVEL == 2
+    a20_mask   = 0xffffff;   /* 286: enable all 24 address lines */
+#else /* 386+ */
+    a20_mask   = 0xffffffff; /* 386: enable all 32 address lines */
+#endif
+    }
+  else {
+    enable_a20 = 0;
+    a20_mask   = 0xffefffff;   /* mask off A20 address line */
+    }
+
+  BX_DBG_A20_REPORT(value);
+
+  BX_DEBUG(("A20: set() = %u", (unsigned) enable_a20));
+
+  // If there has been a transition, we need to notify the CPUs so
+  // they can potentially invalidate certain cache info based on
+  // A20-line-applied physical addresses.
+  if (old_enable_a20 != enable_a20) {
+    for (unsigned i=0; i<BX_SMP_PROCESSORS; i++)
+      BX_CPU(i)->pagingA20Changed();
+    }
+#else
+  BX_DEBUG(("set_enable_a20: ignoring: SUPPORT_A20 = 0"));
+#endif  // #if BX_SUPPORT_A20
+
+#endif
+}
+
+  bx_bool
+bx_pc_system_c::get_enable_a20(void)
+{
+#if BX_SUPPORT_A20
+  if (bx_dbg.a20)
+    BX_INFO(("A20: get() = %u", (unsigned) enable_a20));
+
+  if (enable_a20) return(1);
+  else return(0);
+#else
+  BX_INFO(("get_enable_a20: ignoring: SUPPORT_A20 = 0"));
+  return(1);
+#endif  // #if BX_SUPPORT_A20
+}
+
+  int
+bx_pc_system_c::ResetSignal( PCS_OP operation )
+{
+  UNUSED( operation );
+  // Reset the processor.
+
+  BX_ERROR(( "# bx_pc_system_c::ResetSignal() called" ));
+  for (int i=0; i<BX_SMP_PROCESSORS; i++)
+    BX_CPU(i)->reset(BX_RESET_SOFTWARE);
+  DEV_reset_devices(BX_RESET_SOFTWARE);
+  return(0);
+}
+
+
+  Bit8u
+bx_pc_system_c::IAC(void)
+{
+  return( DEV_pic_iac() );
+}
+
+  void
+bx_pc_system_c::exit(void)
+{
+  if (DEV_hd_present())
+    DEV_hd_close_harddrive();
+
+  BX_INFO(("Last time is %u", (unsigned) DEV_cmos_get_timeval()));
+
+  if (bx_gui) bx_gui->exit();
+}
+
+
+// ================================================
+// Bochs internal timer delivery framework features
+// ================================================
+
+  int
+bx_pc_system_c::register_timer( void *this_ptr, void (*funct)(void *),
+  Bit32u useconds, bx_bool continuous, bx_bool active, const char *id)
+{
+  Bit64u ticks;
+
+  // Convert useconds to number of ticks.
+  ticks = (Bit64u) (double(useconds) * m_ips);
+
+  return register_timer_ticks(this_ptr, funct, ticks, continuous, active, id);
+}
+
+  int
+bx_pc_system_c::register_timer_ticks(void* this_ptr, bx_timer_handler_t funct,
+    Bit64u ticks, bx_bool continuous, bx_bool active, const char *id)
+{
+  unsigned i;
+
+#if BX_TIMER_DEBUG
+  if (numTimers >= BX_MAX_TIMERS) {
+    BX_PANIC(("register_timer: too many registered timers."));
+    }
+  if (this_ptr == NULL)
+    BX_PANIC(("register_timer_ticks: this_ptr is NULL"));
+  if (funct == NULL)
+    BX_PANIC(("register_timer_ticks: funct is NULL"));
+#endif
+
+  // If the timer frequency is rediculously low, make it more sane.
+  // This happens when 'ips' is too low.
+  if (ticks < MinAllowableTimerPeriod) {
+    //BX_INFO(("register_timer_ticks: adjusting ticks of %llu to min of %u",
+    //          ticks, MinAllowableTimerPeriod));
+    ticks = MinAllowableTimerPeriod;
+    }
+
+  for (i=0; i < numTimers; i++) {
+    if (timer[i].inUse == 0)
+      break;
+    }
+
+  timer[i].inUse      = 1;
+  timer[i].period     = ticks;
+  timer[i].timeToFire = (ticksTotal + Bit64u(currCountdownPeriod-currCountdown)) +
+                        ticks;
+  timer[i].active     = active;
+  timer[i].continuous = continuous;
+  timer[i].funct      = funct;
+  timer[i].this_ptr   = this_ptr;
+  strncpy(timer[i].id, id, BxMaxTimerIDLen);
+  timer[i].id[BxMaxTimerIDLen-1] = 0; // Null terminate if not already.
+
+  if (active) {
+    if (ticks < Bit64u(currCountdown)) {
+      // This new timer needs to fire before the current countdown.
+      // Skew the current countdown and countdown period to be smaller
+      // by the delta.
+      currCountdownPeriod -= (currCountdown - Bit32u(ticks));
+      currCountdown = Bit32u(ticks);
+      }
+    }
+
+  // If we didn't find a free slot, increment the bound, numTimers.
+  if (i==numTimers)
+    numTimers++; // One new timer installed.
+
+  // Return timer id.
+  return(i);
+}
+
+
+  void
+bx_pc_system_c::countdownEvent(void)
+{
+  unsigned i;
+  Bit64u   minTimeToFire;
+  bx_bool  triggered[BX_MAX_TIMERS];
+
+  // The countdown decremented to 0.  We need to service all the active
+  // timers, and invoke callbacks from those timers which have fired.
+#if BX_TIMER_DEBUG
+  if (currCountdown != 0)
+    BX_PANIC(("countdownEvent: ticks!=0"));
+#endif
+
+  // Increment global ticks counter by number of ticks which have
+  // elapsed since the last update.
+  ticksTotal += Bit64u(currCountdownPeriod);
+  minTimeToFire = (Bit64u) -1;
+
+  for (i=0; i < numTimers; i++) {
+    triggered[i] = 0; // Reset triggered flag.
+    if (timer[i].active) {
+#if BX_TIMER_DEBUG
+      if (ticksTotal > timer[i].timeToFire)
+        BX_PANIC(("countdownEvent: ticksTotal > timeToFire[%u], D " FMT_LL "u", i,
+                  timer[i].timeToFire-ticksTotal));
+#endif
+      if (ticksTotal == timer[i].timeToFire) {
+        // This timer is ready to fire.
+        triggered[i] = 1;
+
+        if (timer[i].continuous==0) {
+          // If triggered timer is one-shot, deactive.
+          timer[i].active = 0;
+          }
+        else {
+          // Continuous timer, increment time-to-fire by period.
+          timer[i].timeToFire += timer[i].period;
+          if (timer[i].timeToFire < minTimeToFire)
+            minTimeToFire = timer[i].timeToFire;
+          }
+        }
+      else {
+        // This timer is not ready to fire yet.
+        if (timer[i].timeToFire < minTimeToFire)
+          minTimeToFire = timer[i].timeToFire;
+        }
+      }
+    }
+
+  // Calculate next countdown period.  We need to do this before calling
+  // any of the callbacks, as they may call timer features, which need
+  // to be advanced to the next countdown cycle.
+  currCountdown = currCountdownPeriod =
+      Bit32u(minTimeToFire - ticksTotal);
+
+  for (i=0; i < numTimers; i++) {
+    // Call requested timer function.  It may request a different
+    // timer period or deactivate etc.
+    if (triggered[i]) {
+      timer[i].funct(timer[i].this_ptr);
+      }
+    }
+}
+
+  void
+bx_pc_system_c::nullTimer(void* this_ptr)
+{
+  // This function is always inserted in timer[0].  It is sort of
+  // a heartbeat timer.  It ensures that at least one timer is
+  // always active to make the timer logic more simple, and has
+  // a duration of less than the maximum 32-bit integer, so that
+  // a 32-bit size can be used for the hot countdown timer.  The
+  // rest of the timer info can be 64-bits.  This is also a good
+  // place for some logic to report actual emulated
+  // instructions-per-second (IPS) data when measured relative to
+  // the host computer's wall clock.
+
+  UNUSED(this_ptr);
+
+#if SpewPeriodicTimerInfo
+  BX_INFO(("==================================="));
+  for (unsigned i=0; i < bx_pc_system.numTimers; i++) {
+    if (bx_pc_system.timer[i].active) {
+      BX_INFO(("BxTimer(%s): period=" FMT_LL "u, continuous=%u",
+               bx_pc_system.timer[i].id, bx_pc_system.timer[i].period,
+               bx_pc_system.timer[i].continuous));
+      }
+    }
+#endif
+}
+
+#if BX_DEBUGGER
+  void
+bx_pc_system_c::timebp_handler(void* this_ptr)
+{
+      BX_CPU(0)->break_point = BREAK_POINT_TIME;
+      BX_DEBUG(( "Time breakpoint triggered" ));
+
+      if (timebp_queue_size > 1) {
+           Bit64s new_diff = timebp_queue[1] - bx_pc_system.time_ticks();
+           bx_pc_system.activate_timer_ticks(timebp_timer, new_diff, 1);
+      }
+      timebp_queue_size--;
+      for (int i = 0; i < timebp_queue_size; i++)
+           timebp_queue[i] = timebp_queue[i+1];
+}
+#endif // BX_DEBUGGER
+
+  Bit64u
+bx_pc_system_c::time_usec_sequential() {
+    Bit64u this_time_usec = time_usec();
+    if(this_time_usec != lastTimeUsec) {
+      Bit64u diff_usec = this_time_usec-lastTimeUsec;
+      lastTimeUsec = this_time_usec;
+      if(diff_usec >= usecSinceLast) {
+       usecSinceLast = 0;
+      } else {
+       usecSinceLast -= diff_usec;
+      }
+    }
+    usecSinceLast++;
+    return (this_time_usec+usecSinceLast);
+}
+  Bit64u
+bx_pc_system_c::time_usec() {
+  return (Bit64u) (((double)(Bit64s)time_ticks()) / m_ips );
+}
+
+  void
+bx_pc_system_c::start_timers(void)
+{
+}
+
+  void
+bx_pc_system_c::activate_timer_ticks(unsigned i, Bit64u ticks, bx_bool continuous)
+{
+#if BX_TIMER_DEBUG
+  if (i >= numTimers)
+    BX_PANIC(("activate_timer_ticks: timer %u OOB", i));
+  if (timer[i].period < MinAllowableTimerPeriod)
+    BX_PANIC(("activate_timer_ticks: timer[%u].period of " FMT_LL "u < min of %u",
+              i, timer[i].period, MinAllowableTimerPeriod));
+#endif
+
+  // If the timer frequency is rediculously low, make it more sane.
+  // This happens when 'ips' is too low.
+  if (ticks < MinAllowableTimerPeriod) {
+    //BX_INFO(("activate_timer_ticks: adjusting ticks of %llu to min of %u",
+    //          ticks, MinAllowableTimerPeriod));
+    ticks = MinAllowableTimerPeriod;
+    }
+
+  timer[i].period = ticks;
+  timer[i].timeToFire = (ticksTotal + Bit64u(currCountdownPeriod-currCountdown)) +
+                        ticks;
+  timer[i].active     = 1;
+  timer[i].continuous = continuous;
+
+  if (ticks < Bit64u(currCountdown)) {
+    // This new timer needs to fire before the current countdown.
+    // Skew the current countdown and countdown period to be smaller
+    // by the delta.
+    currCountdownPeriod -= (currCountdown - Bit32u(ticks));
+    currCountdown = Bit32u(ticks);
+    }
+}
+
+  void
+bx_pc_system_c::activate_timer(unsigned i, Bit32u useconds, bx_bool continuous)
+{
+  Bit64u ticks;
+
+#if BX_TIMER_DEBUG
+  if (i >= numTimers)
+    BX_PANIC(("activate_timer: timer %u OOB", i));
+#endif
+
+  // if useconds = 0, use default stored in period field
+  // else set new period from useconds
+  if (useconds==0) {
+    ticks = timer[i].period;
+    }
+  else {
+    // convert useconds to number of ticks
+    ticks = (Bit64u) (double(useconds) * m_ips);
+
+    // If the timer frequency is rediculously low, make it more sane.
+    // This happens when 'ips' is too low.
+    if (ticks < MinAllowableTimerPeriod) {
+      //BX_INFO(("activate_timer: adjusting ticks of %llu to min of %u",
+      //          ticks, MinAllowableTimerPeriod));
+      ticks = MinAllowableTimerPeriod;
+      }
+
+    timer[i].period = ticks;
+    }
+
+  activate_timer_ticks(i, ticks, continuous);
+}
+
+  void
+bx_pc_system_c::deactivate_timer( unsigned i )
+{
+#if BX_TIMER_DEBUG
+  if (i >= numTimers)
+    BX_PANIC(("deactivate_timer: timer %u OOB", i));
+#endif
+
+  timer[i].active = 0;
+}
+
+  unsigned
+bx_pc_system_c::unregisterTimer(int timerIndex)
+{
+  unsigned i = (unsigned) timerIndex;
+
+#if BX_TIMER_DEBUG
+  if (i >= numTimers)
+    BX_PANIC(("unregisterTimer: timer %u OOB", i));
+  if (i == 0)
+    BX_PANIC(("unregisterTimer: timer 0 is the nullTimer!"));
+  if (timer[i].inUse == 0)
+    BX_PANIC(("unregisterTimer: timer %u is not in-use!", i));
+#endif
+
+  if (timer[i].active) {
+    BX_PANIC(("unregisterTimer: timer '%s' is still active!", timer[i].id));
+    return(0); // Fail.
+    }
+
+  // Reset timer fields for good measure.
+  timer[i].inUse      = 0; // No longer registered.
+  timer[i].period     = BX_MAX_BIT64S; // Max value (invalid)
+  timer[i].timeToFire = BX_MAX_BIT64S; // Max value (invalid)
+  timer[i].continuous = 0;
+  timer[i].funct      = NULL;
+  timer[i].this_ptr   = NULL;
+  memset(timer[i].id, 0, BxMaxTimerIDLen);
+
+  return(1); // OK
+}
diff --git a/tools/ioemu/iodev/pci.cc b/tools/ioemu/iodev/pci.cc
new file mode 100644 (file)
index 0000000..6dfe5db
--- /dev/null
@@ -0,0 +1,467 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci.cc,v 1.29 2003/07/31 19:51:42 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// i440FX Support - PMC/DBX
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_PCI_SUPPORT
+
+#define LOG_THIS thePciBridge->
+
+bx_pci_c *thePciBridge = NULL;
+
+  int
+libpci_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  thePciBridge = new bx_pci_c ();
+  bx_devices.pluginPciBridge = thePciBridge;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciBridge, BX_PLUGIN_PCI);
+  return(0); // Success
+}
+
+  void
+libpci_LTX_plugin_fini(void)
+{
+}
+
+bx_pci_c::bx_pci_c(void)
+{
+  put("PCI");
+  settype(PCILOG);
+}
+
+bx_pci_c::~bx_pci_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_pci_c::init(void)
+{
+  // called once when bochs initializes
+  unsigned i;
+  BX_PCI_THIS num_pci_handles = 0;
+
+  /* set unused elements to appropriate values */
+  for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
+    BX_PCI_THIS pci_handler[i].read  = NULL;
+    BX_PCI_THIS pci_handler[i].write = NULL;
+    }
+
+  for (i=0; i < 0x100; i++) {
+    BX_PCI_THIS pci_handler_id[i] = BX_MAX_PCI_DEVICES;  // not assigned
+  }
+
+  // confAddr accepts dword i/o only
+  DEV_register_ioread_handler(this, read_handler, 0x0CF8, "i440FX", 4);
+  DEV_register_iowrite_handler(this, write_handler, 0x0CF8, "i440FX", 4);
+
+  for (i=0x0CFC; i<=0x0CFF; i++) {
+    DEV_register_ioread_handler(this, read_handler, i, "i440FX", 7);
+  }
+  for (i=0x0CFC; i<=0x0CFF; i++) {
+    DEV_register_iowrite_handler(this, write_handler, i, "i440FX", 7);
+  }
+
+  DEV_register_pci_handlers(this, pci_read_handler, pci_write_handler,
+                            BX_PCI_DEVICE(0,0), "440FX Host bridge");
+
+  for (i=0; i<256; i++)
+    BX_PCI_THIS s.i440fx.pci_conf[i] = 0x0;
+  // readonly registers
+  BX_PCI_THIS s.i440fx.pci_conf[0x00] = 0x86;
+  BX_PCI_THIS s.i440fx.pci_conf[0x01] = 0x80;
+  BX_PCI_THIS s.i440fx.pci_conf[0x02] = 0x37;
+  BX_PCI_THIS s.i440fx.pci_conf[0x03] = 0x12;
+  BX_PCI_THIS s.i440fx.pci_conf[0x0b] = 0x06;
+}
+
+  void
+bx_pci_c::reset(unsigned type)
+{
+  BX_PCI_THIS s.i440fx.confAddr = 0;
+  BX_PCI_THIS s.i440fx.confData = 0;
+
+  BX_PCI_THIS s.i440fx.pci_conf[0x04] = 0x06;
+  BX_PCI_THIS s.i440fx.pci_conf[0x05] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x06] = 0x80;
+  BX_PCI_THIS s.i440fx.pci_conf[0x07] = 0x02;
+  BX_PCI_THIS s.i440fx.pci_conf[0x0d] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x0f] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x50] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x51] = 0x01;
+  BX_PCI_THIS s.i440fx.pci_conf[0x52] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x53] = 0x80;
+  BX_PCI_THIS s.i440fx.pci_conf[0x54] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x55] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x56] = 0x00;
+  BX_PCI_THIS s.i440fx.pci_conf[0x57] = 0x01;
+  BX_PCI_THIS s.i440fx.pci_conf[0x58] = 0x10;
+  for (unsigned i=0x59; i<0x60; i++)
+    BX_PCI_THIS s.i440fx.pci_conf[i] = 0x00;
+}
+
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pci_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+  bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pci_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+  switch (address) {
+    case 0x0CF8:
+      {
+        return BX_PCI_THIS s.i440fx.confAddr;
+      }
+      break;
+    case 0x0CFC:
+    case 0x0CFD:
+    case 0x0CFE:
+    case 0x0CFF:
+      {
+      Bit32u handle, retval;
+      Bit8u devfunc, regnum;
+
+      if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
+        devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
+        regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
+        handle = BX_PCI_THIS pci_handler_id[devfunc];
+        if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES))
+          retval = (* BX_PCI_THIS pci_handler[handle].read)
+                     (BX_PCI_THIS pci_handler[handle].this_ptr, regnum, io_len);
+        else
+          retval = 0xFFFFFFFF;
+        }
+      else
+        retval = 0xFFFFFFFF;
+      BX_PCI_THIS s.i440fx.confData = retval;
+      return retval;
+      }
+    }
+
+  BX_PANIC(("unsupported IO read to port 0x%x",
+           (unsigned) address));
+  return(0xffffffff);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pci_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+  bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_pci_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+  switch (address) {
+    case 0xCF8:
+      {
+        BX_PCI_THIS s.i440fx.confAddr = value;
+        if ((value & 0x80FFFF00) == 0x80000000) {
+          BX_DEBUG(("440FX PMC register 0x%02x selected", value & 0xfc));
+        } else if ((value & 0x80000000) == 0x80000000) {
+          BX_DEBUG(("440FX request for bus 0x%02x device 0x%02x function 0x%02x",
+                    (value >> 16) & 0xFF, (value >> 11) & 0x1F, (value >> 8) & 0x07));
+        }
+      }
+      break;
+
+    case 0xCFC:
+    case 0xCFD:
+    case 0xCFE:
+    case 0xCFF:
+      {
+      Bit32u handle;
+      Bit8u devfunc, regnum;
+
+      if ((BX_PCI_THIS s.i440fx.confAddr & 0x80FF0000) == 0x80000000) {
+        devfunc = (BX_PCI_THIS s.i440fx.confAddr >> 8) & 0xff;
+        regnum = (BX_PCI_THIS s.i440fx.confAddr & 0xfc) + (address & 0x03);
+        handle = BX_PCI_THIS pci_handler_id[devfunc];
+        if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
+          if (((regnum>=4) && (regnum<=7)) || (regnum==12) || (regnum==13) || (regnum>14)) {
+            (* BX_PCI_THIS pci_handler[handle].write)
+               (BX_PCI_THIS pci_handler[handle].this_ptr, regnum, value, io_len);
+            BX_PCI_THIS s.i440fx.confData = value << (8 * (address & 0x03));
+            }
+          else
+            BX_DEBUG(("read only register, write ignored"));
+          }
+        }
+      }
+      break;
+
+    default:
+      BX_PANIC(("IO write to port 0x%x", (unsigned) address));
+    }
+}
+
+
+  // static pci configuration space read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pci_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+  bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+  return( class_ptr->pci_read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pci_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+  Bit32u val440fx = 0;
+
+  if (io_len <= 4) {
+    for (unsigned i=0; i<io_len; i++) {
+      val440fx |= (BX_PCI_THIS s.i440fx.pci_conf[address+i] << (i*8));
+    }
+    BX_DEBUG(("440FX PMC read register 0x%02x value 0x%08x", address, val440fx));
+    return val440fx;
+    }
+  else
+    return(0xffffffff);
+}
+
+
+  // static pci configuration space write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pci_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCI_SMF
+  bx_pci_c *class_ptr = (bx_pci_c *) this_ptr;
+
+  class_ptr->pci_write(address, value, io_len);
+}
+
+  void
+bx_pci_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCI_SMF
+
+  Bit8u value8;
+
+  if (io_len <= 4) {
+    for (unsigned i=0; i<io_len; i++) {
+      value8 = (value >> (i*8)) & 0xFF;
+      switch (address+i) {
+        case 0x06:
+        case 0x0c:
+          break;
+        default:
+          BX_PCI_THIS s.i440fx.pci_conf[address+i] = value8;
+          BX_DEBUG(("440FX PMC write register 0x%02x value 0x%02x", address,
+                    value8));
+        }
+      }
+    }
+}
+
+
+  Bit8u
+bx_pci_c::rd_memType (Bit32u addr)
+{
+   switch ((addr & 0xFC000) >> 12) {
+      case 0xC0:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5A] & 0x1);
+      case 0xC4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 4) & 0x1);
+      case 0xC8:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5B] & 0x1);
+      case 0xCC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 4) & 0x1);
+
+
+      case 0xD0:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5C] & 0x1);
+      case 0xD4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 4) & 0x1);
+      case 0xD8:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5D] & 0x1);
+      case 0xDC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 4) & 0x1);
+
+      case 0xE0:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5E] & 0x1);
+      case 0xE4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 4) & 0x1);
+      case 0xE8:
+           return (BX_PCI_THIS s.i440fx.pci_conf[0x5F] & 0x1);
+      case 0xEC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 4) & 0x1);
+
+      case 0xF0:
+      case 0xF4:
+      case 0xF8:
+      case 0xFC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 4) & 0x1);
+
+      default:
+           BX_PANIC(("rd_memType () Error: Memory Type not known !"));
+           return(0); // keep compiler happy
+           break;
+   }
+
+}
+
+  Bit8u
+bx_pci_c::wr_memType (Bit32u addr)
+{
+   switch ((addr & 0xFC000) >> 12) {
+      case 0xC0:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 1) & 0x1);
+      case 0xC4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5A] >> 5) & 0x1);
+      case 0xC8:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 1) & 0x1);
+      case 0xCC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5B] >> 5) & 0x1);
+
+
+      case 0xD0:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 1) & 0x1);
+      case 0xD4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5C] >> 5) & 0x1);
+      case 0xD8:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 1) & 0x1);
+      case 0xDC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5D] >> 5) & 0x1);
+
+      case 0xE0:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 1) & 0x1);
+      case 0xE4:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5E] >> 5) & 0x1);
+      case 0xE8:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 1) & 0x1);
+      case 0xEC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x5F] >> 5) & 0x1);
+
+      case 0xF0:
+      case 0xF4:
+      case 0xF8:
+      case 0xFC:
+           return ( (BX_PCI_THIS s.i440fx.pci_conf[0x59] >> 5) & 0x1);
+
+      default:
+           BX_PANIC(("wr_memType () Error: Memory Type not known !"));
+           return(0); // keep compiler happy
+           break;
+   }
+}
+
+  void
+bx_pci_c::print_i440fx_state()
+{
+  int  i;
+
+  BX_DEBUG(( "i440fxConfAddr:0x%08x", BX_PCI_THIS s.i440fx.confAddr ));
+  BX_DEBUG(( "i440fxConfData:0x%08x", BX_PCI_THIS s.i440fx.confData ));
+
+#ifdef DUMP_FULL_I440FX
+  for (i=0; i<256; i++) {
+    BX_DEBUG(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i] ));
+    }
+#else /* DUMP_FULL_I440FX */
+  for (i=0x59; i<0x60; i++) {
+    BX_DEBUG(( "i440fxArray%02x:0x%02x", i, BX_PCI_THIS s.i440fx.pci_conf[i] ));
+    }
+#endif /* DUMP_FULL_I440FX */
+}
+
+  bx_bool
+bx_pci_c::register_pci_handlers( void *this_ptr, bx_pci_read_handler_t f1,
+                                 bx_pci_write_handler_t f2, Bit8u devfunc,
+                                 const char *name)
+{
+  unsigned handle;
+
+  /* first check if device/function is available */
+  if (BX_PCI_THIS pci_handler_id[devfunc] == BX_MAX_PCI_DEVICES) {
+    if (BX_PCI_THIS num_pci_handles >= BX_MAX_PCI_DEVICES) {
+      BX_INFO(("too many PCI devices installed."));
+      BX_PANIC(("  try increasing BX_MAX_PCI_DEVICES"));
+      return false;
+      }
+    handle = BX_PCI_THIS num_pci_handles++;
+    BX_PCI_THIS pci_handler[handle].read  = f1;
+    BX_PCI_THIS pci_handler[handle].write = f2;
+    BX_PCI_THIS pci_handler[handle].this_ptr = this_ptr;
+    BX_PCI_THIS pci_handler_id[devfunc] = handle;
+    BX_INFO(("%s present at device %d, function %d", name, devfunc >> 3,
+             devfunc & 0x07));
+    return true; // device/function mapped successfully
+    }
+  else {
+    return false; // device/function not available, return false.
+    }
+}
+#endif /* BX_PCI_SUPPORT */
diff --git a/tools/ioemu/iodev/pci.h b/tools/ioemu/iodev/pci.h
new file mode 100644 (file)
index 0000000..92e7bee
--- /dev/null
@@ -0,0 +1,90 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci.h,v 1.14 2003/01/23 19:31:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#define BX_MAX_PCI_DEVICES 20
+
+#define BX_PCI_DEVICE(device, function) ((device)<<3 | (function))
+
+typedef Bit32u (*bx_pci_read_handler_t)(void *, Bit8u, unsigned);
+typedef void   (*bx_pci_write_handler_t)(void *, Bit8u, Bit32u, unsigned);
+
+#if BX_USE_PCI_SMF
+#  define BX_PCI_SMF  static
+#  define BX_PCI_THIS thePciBridge->
+#else
+#  define BX_PCI_SMF
+#  define BX_PCI_THIS this->
+#endif
+
+
+typedef struct {
+  Bit32u confAddr;
+  Bit32u confData;
+  Bit8u  pci_conf[256];
+  } bx_def440fx_t;
+
+
+
+class bx_pci_c : public bx_pci_stub_c {
+
+public:
+  bx_pci_c(void);
+  ~bx_pci_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+  virtual bx_bool register_pci_handlers(void *this_ptr,
+                                        bx_pci_read_handler_t f1,
+                                        bx_pci_write_handler_t f2,
+                                        Bit8u devfunc, const char *name);
+  virtual void   print_i440fx_state(void);
+  virtual Bit8u rd_memType (Bit32u addr);
+  virtual Bit8u wr_memType (Bit32u addr);
+
+private:
+  Bit8u pci_handler_id[0x100];  // 256 devices/functions
+  struct {
+    bx_pci_read_handler_t  read;
+    bx_pci_write_handler_t write;
+    void             *this_ptr;
+    } pci_handler[BX_MAX_PCI_DEVICES];
+  unsigned num_pci_handles;
+
+  struct {
+    bx_def440fx_t i440fx;
+    } s;
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+  static void   pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PCI_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+  Bit32u pci_read(Bit8u address, unsigned io_len);
+  void   pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+  };
diff --git a/tools/ioemu/iodev/pci2isa.cc b/tools/ioemu/iodev/pci2isa.cc
new file mode 100644 (file)
index 0000000..54c3bc4
--- /dev/null
@@ -0,0 +1,294 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci2isa.cc,v 1.10 2003/07/31 19:51:42 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// i440FX Support - PCI-to-ISA bridge (PIIX3)
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_PCI_SUPPORT
+
+#define LOG_THIS thePci2IsaBridge->
+
+bx_pci2isa_c *thePci2IsaBridge = NULL;
+
+  int
+libpci2isa_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  thePci2IsaBridge = new bx_pci2isa_c ();
+  bx_devices.pluginPci2IsaBridge = thePci2IsaBridge;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePci2IsaBridge, BX_PLUGIN_PCI2ISA);
+  return(0); // Success
+}
+
+  void
+libpci2isa_LTX_plugin_fini(void)
+{
+}
+
+bx_pci2isa_c::bx_pci2isa_c(void)
+{
+  put("P2I");
+  settype(PCI2ISALOG);
+}
+
+bx_pci2isa_c::~bx_pci2isa_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_pci2isa_c::init(void)
+{
+  // called once when bochs initializes
+
+  DEV_register_pci_handlers(this, pci_read_handler, pci_write_handler,
+                            BX_PCI_DEVICE(1,0), "PIIX3 PCI-to-ISA bridge");
+
+  DEV_register_iowrite_handler(this, write_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
+
+  DEV_register_ioread_handler(this, read_handler, 0x00B2, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x00B3, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x04D0, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x04D1, "PIIX3 PCI-to-ISA bridge", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0CF9, "PIIX3 PCI-to-ISA bridge", 1);
+
+  for (unsigned i=0; i<256; i++)
+    BX_P2I_THIS s.pci_conf[i] = 0x0;
+  // readonly registers
+  BX_P2I_THIS s.pci_conf[0x00] = 0x86;
+  BX_P2I_THIS s.pci_conf[0x01] = 0x80;
+  BX_P2I_THIS s.pci_conf[0x02] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x03] = 0x70;
+  BX_P2I_THIS s.pci_conf[0x0a] = 0x01;
+  BX_P2I_THIS s.pci_conf[0x0b] = 0x06;
+  BX_P2I_THIS s.pci_conf[0x0e] = 0x80;
+}
+
+  void
+bx_pci2isa_c::reset(unsigned type)
+{
+  BX_P2I_THIS s.pci_conf[0x04] = 0x07;
+  BX_P2I_THIS s.pci_conf[0x05] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x06] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x07] = 0x02;
+  BX_P2I_THIS s.pci_conf[0x4c] = 0x4d;
+  BX_P2I_THIS s.pci_conf[0x4e] = 0x03;
+  BX_P2I_THIS s.pci_conf[0x4f] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x60] = 0x80;
+  BX_P2I_THIS s.pci_conf[0x69] = 0x02;
+  BX_P2I_THIS s.pci_conf[0x70] = 0x80;
+  BX_P2I_THIS s.pci_conf[0x76] = 0x0c;
+  BX_P2I_THIS s.pci_conf[0x77] = 0x0c;
+  BX_P2I_THIS s.pci_conf[0x78] = 0x02;
+  BX_P2I_THIS s.pci_conf[0x79] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x80] = 0x00;
+  BX_P2I_THIS s.pci_conf[0x82] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa0] = 0x08;
+  BX_P2I_THIS s.pci_conf[0xa0] = 0x08;
+  BX_P2I_THIS s.pci_conf[0xa2] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa3] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa4] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa5] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa6] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa7] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xa8] = 0x0f;
+  BX_P2I_THIS s.pci_conf[0xaa] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xab] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xac] = 0x00;
+  BX_P2I_THIS s.pci_conf[0xae] = 0x00;
+
+  BX_P2I_THIS s.elcr1 = 0x00;
+  BX_P2I_THIS s.elcr2 = 0x00;
+}
+
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pci2isa_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+  bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pci2isa_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+  switch (address) {
+    case 0x00b2:
+      BX_ERROR(("read: APM command register not supported yet"));
+      break;
+    case 0x00b3:
+      BX_ERROR(("read: APM status register not supported yet"));
+      break;
+    case 0x04d0:
+      return(BX_P2I_THIS s.elcr1);
+      break;
+    case 0x04d1:
+      return(BX_P2I_THIS s.elcr2);
+      break;
+    case 0x0cf9:
+      BX_ERROR(("read: CPU reset register not supported yet"));
+      break;
+    }
+
+  return(0xffffffff);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pci2isa_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+  bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_pci2isa_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+  switch (address) {
+    case 0x00b2:
+      BX_ERROR(("write: APM command register not supported yet"));
+      break;
+    case 0x00b3:
+      BX_ERROR(("write: APM status register not supported yet"));
+      break;
+    case 0x04d0:
+      BX_P2I_THIS s.elcr1 = (value & 0xf8);
+      BX_ERROR(("write: ELCR1 changes have no effect yet"));
+      break;
+    case 0x04d1:
+      BX_P2I_THIS s.elcr2 = (value & 0xde);
+      BX_ERROR(("write: ELCR2 changes have no effect yet"));
+      break;
+    case 0x0cf9:
+      BX_ERROR(("write: CPU reset register not supported yet"));
+      break;
+    }
+}
+
+
+  // static pci configuration space read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pci2isa_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+  bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+  return( class_ptr->pci_read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pci2isa_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+  Bit32u value = 0;
+
+  if (io_len <= 4) {
+    for (unsigned i=0; i<io_len; i++) {
+      value |= (BX_P2I_THIS s.pci_conf[address+i] << (i*8));
+    }
+    BX_DEBUG(("PIIX3 PCI-to-ISA read register 0x%02x value 0x%08x", address, value));
+    return value;
+    }
+  else
+    return(0xffffffff);
+}
+
+
+  // static pci configuration space write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pci2isa_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_P2I_SMF
+  bx_pci2isa_c *class_ptr = (bx_pci2isa_c *) this_ptr;
+
+  class_ptr->pci_write(address, value, io_len);
+}
+
+  void
+bx_pci2isa_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_P2I_SMF
+
+  Bit8u value8;
+
+  if (io_len <= 4) {
+    for (unsigned i=0; i<io_len; i++) {
+      value8 = (value >> (i*8)) & 0xFF;
+      switch (address+i) {
+        case 0x06:
+          break;
+        default:
+          BX_P2I_THIS s.pci_conf[address+i] = value8;
+          BX_DEBUG(("PIIX3 PCI-to-ISA write register 0x%02x value 0x%02x", address,
+                    value8));
+        }
+      }
+    }
+}
+
+#endif /* BX_PCI_SUPPORT */
diff --git a/tools/ioemu/iodev/pci2isa.h b/tools/ioemu/iodev/pci2isa.h
new file mode 100644 (file)
index 0000000..1517052
--- /dev/null
@@ -0,0 +1,63 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pci2isa.h,v 1.4 2002/11/09 20:51:40 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#if BX_USE_P2I_SMF
+#  define BX_P2I_SMF  static
+#  define BX_P2I_THIS thePci2IsaBridge->
+#else
+#  define BX_P2I_SMF
+#  define BX_P2I_THIS this->
+#endif
+
+
+class bx_pci2isa_c : public bx_devmodel_c {
+
+public:
+  bx_pci2isa_c(void);
+  ~bx_pci2isa_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+
+  struct {
+    Bit8u pci_conf[256];
+    Bit8u elcr1;
+    Bit8u elcr2; 
+    } s;
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+  static void   pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_P2I_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+  Bit32u pci_read(Bit8u address, unsigned io_len);
+  void   pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+  };
diff --git a/tools/ioemu/iodev/pciusb.cc b/tools/ioemu/iodev/pciusb.cc
new file mode 100644 (file)
index 0000000..e2d4248
--- /dev/null
@@ -0,0 +1,668 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pciusb.cc,v 1.3 2003/02/06 19:09:24 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// Experimental PCI USB adapter
+// Benjamin D Lunt (fys@cybertrails.com) coded most of this usb emulation.
+//  I hope to add to this code to make it more functionable.
+//
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_PCI_SUPPORT && BX_PCI_USB_SUPPORT
+
+#define LOG_THIS theUSBDevice->
+
+bx_pciusb_c* theUSBDevice = NULL;
+
+  int
+libpciusb_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theUSBDevice = new bx_pciusb_c ();
+  bx_devices.pluginPciUSBAdapter = theUSBDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUSBDevice, BX_PLUGIN_PCIUSB);
+  return 0; // Success
+}
+
+  void
+libpciusb_LTX_plugin_fini(void)
+{
+}
+
+
+bx_pciusb_c::bx_pciusb_c(void)
+{
+  put("USB");
+  settype(PCIUSBLOG);
+}
+
+bx_pciusb_c::~bx_pciusb_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_pciusb_c::init(void)
+{
+  // called once when bochs initializes
+
+  if (!bx_options.usb[0].Oenabled->get()) return;
+
+  Bit16u base_ioaddr = bx_options.usb[0].Oioaddr->get();
+  Bit8u irq = bx_options.usb[0].Oirq->get();
+
+  DEV_register_irq(irq, "USB Hub #1");
+  BX_USB_THIS hub[0].irq = irq;
+
+  // Call our timer routine every 1mS (1,000uS)
+  // Continuous and active
+  BX_USB_THIS hub[0].timer_index =
+                   bx_pc_system.register_timer(this, usb_timer_handler, 1000, 1,1, "usb.timer");
+
+  for (unsigned addr=base_ioaddr; addr<(unsigned)(base_ioaddr+0x14); addr++) {
+    BX_DEBUG(("register read/write: 0x%04x", addr));
+    DEV_register_ioread_handler(this, read_handler, addr, "USB Hub #1", 7);
+    DEV_register_iowrite_handler(this, write_handler, addr, "USB Hub #1", 7);
+  }
+  BX_USB_THIS hub[0].base_ioaddr = base_ioaddr;
+
+  DEV_register_pci_handlers(this,
+                            pci_read_handler,
+                            pci_write_handler,
+                            BX_PCI_DEVICE(1,2),
+                            "Experimental PCI USB");
+
+  for (unsigned i=0; i<256; i++) {
+    BX_USB_THIS hub[0].pci_conf[i] = 0x0;
+  }
+
+  BX_INFO(("usb1 at 0x%04x-0x%04x irq %d", base_ioaddr, base_ioaddr+0x13, irq));
+}
+
+  void
+bx_pciusb_c::reset(unsigned type)
+{
+  unsigned i;
+
+  static const struct reset_vals_t {
+    unsigned      addr;
+    unsigned char val;
+  } reset_vals[] = {
+    { 0x00, 0x86 }, { 0x01, 0x80 }, // 0x8086 = vendor
+    { 0x02, 0x20 }, { 0x03, 0x70 }, // 0x7020 = device
+    { 0x04, 0x05 }, { 0x05, 0x00 },    // command_io
+    { 0x06, 0x80 }, { 0x07, 0x02 },    // status
+    { 0x08, 0x01 },                 // revision number
+    { 0x09, 0x00 },                 // interface
+    { 0x0a, 0x03 },                 // class_sub  USB Host Controller
+    { 0x0b, 0x0c },                 // class_base Serial Bus Controller
+    { 0x0D, 0x20 },                 // bus latency
+    { 0x0e, 0x00 },                 // header_type_generic
+    // address space 0x20 - 0x23
+    { 0x20, ((bx_options.usb[0].Oioaddr->get() & 0xE0) | 0x01) },
+    { 0x21, (bx_options.usb[0].Oioaddr->get() >> 8) },
+    { 0x22, 0x00 }, { 0x23, 0x00 },
+    { 0x3c, bx_options.usb[0].Oirq->get() }, // IRQ
+    { 0x3d, 0x04 },                 // INT
+    { 0x6a, 0x01 },                 // USB clock
+    { 0xc1, 0x20 }                  // PIRQ enable
+
+  };
+  for (i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
+      BX_USB_THIS hub[0].pci_conf[reset_vals[i].addr] = reset_vals[i].val;
+  }
+
+  // reset locals
+  BX_USB_THIS global_reset = 0;
+
+  // Put the USB registers into their RESET state
+  for (i=0; i<BX_USB_CONFDEV; i++) {
+    BX_USB_THIS hub[i].usb_command.max_packet_size = 0;
+    BX_USB_THIS hub[i].usb_command.configured = 0;
+    BX_USB_THIS hub[i].usb_command.debug = 0;
+    BX_USB_THIS hub[i].usb_command.resume = 0;
+    BX_USB_THIS hub[i].usb_command.suspend = 1;
+    BX_USB_THIS hub[i].usb_command.host_reset = 0;
+    BX_USB_THIS hub[i].usb_command.reset = 0;
+    BX_USB_THIS hub[i].usb_command.schedule = 0;
+    BX_USB_THIS hub[i].usb_status.error_interrupt = 0;
+    BX_USB_THIS hub[i].usb_status.host_error = 0;
+    BX_USB_THIS hub[i].usb_status.host_halted = 0;
+    BX_USB_THIS hub[i].usb_status.interrupt = 0;
+    BX_USB_THIS hub[i].usb_status.pci_error = 0;
+    BX_USB_THIS hub[i].usb_status.resume = 0;
+    BX_USB_THIS hub[i].usb_enable.short_packet = 0;
+    BX_USB_THIS hub[i].usb_enable.on_complete = 0;
+    BX_USB_THIS hub[i].usb_enable.resume = 0;
+    BX_USB_THIS hub[i].usb_enable.timeout_crc = 0;
+    BX_USB_THIS hub[i].usb_frame_num.frame_num = 0x0000;
+    BX_USB_THIS hub[i].usb_frame_base.frame_base = 0x00000000;
+    BX_USB_THIS hub[i].usb_sof.sof_timing = 0x40;
+    for (unsigned j=0; j<USB_NUM_PORTS; j++) {
+      BX_USB_THIS hub[i].usb_port[j].connect_changed = 0;
+      BX_USB_THIS hub[i].usb_port[j].line_dminus = 0;
+      BX_USB_THIS hub[i].usb_port[j].line_dplus = 0;
+      BX_USB_THIS hub[i].usb_port[j].low_speed = 0;
+      BX_USB_THIS hub[i].usb_port[j].reset = 0;
+      BX_USB_THIS hub[i].usb_port[j].resume = 0;
+      BX_USB_THIS hub[i].usb_port[j].suspend = 0;
+      BX_USB_THIS hub[i].usb_port[j].enabled = 0;
+      BX_USB_THIS hub[i].usb_port[j].able_changed = 0;
+      BX_USB_THIS hub[i].usb_port[j].status = 0;
+    }
+  }
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pciusb_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+  bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pciusb_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+  Bit32u val = 0x0;
+  Bit8u  offset,port;
+
+  BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
+
+  offset = address - BX_USB_THIS hub[0].base_ioaddr;
+
+  switch (offset) {
+    case 0x0C: // Start of Frame Modify
+    case 0x11: // port0 (high byte read)
+    case 0x13: // port1 (high byte read)
+      if (io_len != 1)
+        BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+    case 0x10: // port0
+    case 0x12: // port1
+      if ((io_len < 1) || (io_len > 2))
+        BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+    case 0x00: // command register (16-bit)
+    case 0x02: // status register (16-bit)
+    case 0x04: // interrupt enable register (1-bit)
+    case 0x06: // frame number register (16-bit)
+      if (io_len != 2)
+        BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+    case 0x08: // frame base register (32-bit)
+      if (io_len != 4)
+        BX_PANIC(("io read from port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+  }
+
+  switch (offset) {
+    case 0x00: // command register (16-bit)
+      val = BX_USB_THIS hub[0].usb_command.max_packet_size << 7
+            | BX_USB_THIS hub[0].usb_command.configured << 6
+            | BX_USB_THIS hub[0].usb_command.debug << 5
+            | BX_USB_THIS hub[0].usb_command.resume << 4
+            | BX_USB_THIS hub[0].usb_command.suspend << 3
+            | BX_USB_THIS hub[0].usb_command.reset << 2
+            | BX_USB_THIS hub[0].usb_command.host_reset << 1
+            | BX_USB_THIS hub[0].usb_command.schedule;
+      break;
+
+    case 0x02: // status register (16-bit)
+      val = BX_USB_THIS hub[0].usb_status.host_halted << 5
+            | BX_USB_THIS hub[0].usb_status.host_error << 4
+            | BX_USB_THIS hub[0].usb_status.pci_error << 3
+            | BX_USB_THIS hub[0].usb_status.resume << 2
+            | BX_USB_THIS hub[0].usb_status.error_interrupt << 1
+            | BX_USB_THIS hub[0].usb_status.interrupt;
+      break;
+
+    case 0x04: // interrupt enable register (16-bit)
+      val = BX_USB_THIS hub[0].usb_enable.short_packet << 3
+            | BX_USB_THIS hub[0].usb_enable.on_complete << 2
+            | BX_USB_THIS hub[0].usb_enable.resume << 1
+            | BX_USB_THIS hub[0].usb_enable.timeout_crc;
+      break;
+
+    case 0x06: // frame number register (16-bit)
+      val = BX_USB_THIS hub[0].usb_frame_num.frame_num;
+      break;
+
+    case 0x08: // frame base register (32-bit)
+      val = BX_USB_THIS hub[0].usb_frame_base.frame_base;
+      break;
+
+    case 0x0C: // start of Frame Modify register (8-bit)
+      val = BX_USB_THIS hub[0].usb_sof.sof_timing;
+      break;
+
+    case 0x10: // port0
+    case 0x12: // port1
+      port = (offset & 0x0F) >> 1;
+      if (port < USB_NUM_PORTS) {
+        val = BX_USB_THIS hub[0].usb_port[port].suspend << 12
+              | BX_USB_THIS hub[0].usb_port[port].reset << 9
+              | BX_USB_THIS hub[0].usb_port[port].low_speed << 8
+              | 1 << 7
+              | BX_USB_THIS hub[0].usb_port[port].resume << 6
+              | BX_USB_THIS hub[0].usb_port[port].line_dplus << 5
+              | BX_USB_THIS hub[0].usb_port[port].line_dminus << 4
+              | BX_USB_THIS hub[0].usb_port[port].able_changed << 3
+              | BX_USB_THIS hub[0].usb_port[port].enabled << 2
+              | BX_USB_THIS hub[0].usb_port[port].connect_changed << 1
+              | BX_USB_THIS hub[0].usb_port[port].status;
+        break;
+      } // else fall through to default
+
+    default:
+      val = 0; // keep compiler happy
+      BX_PANIC(("unsupported io read from address=0x%04x!", (unsigned) address));
+      break;
+  }
+
+  BX_DEBUG(("val =  0x%08x", (Bit32u) val));
+
+  return(val);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pciusb_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+  bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_pciusb_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+  Bit8u  offset,port;
+
+  BX_DEBUG(("register write to address 0x%04x - ", (unsigned) address));
+
+  offset = address - BX_USB_THIS hub[0].base_ioaddr;
+
+  switch (offset) {
+    case 0x0C: // Start of Frame Modify
+      if (io_len != 1)
+        BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+    case 0x00: // command register (16-bit)
+    case 0x02: // status register (16-bit)
+    case 0x04: // interrupt enable register (1-bit)
+    case 0x06: // frame number register (16-bit)
+    case 0x10: // port0
+    case 0x12: // port1
+      if (io_len != 2)
+        BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+    case 0x08: // frame base register (32-bit)
+      if (io_len != 4)
+        BX_PANIC(("io write to port 0x%04x, bad len=%u", (unsigned) address, (unsigned) io_len));
+      break;
+  }
+
+  switch (offset) {
+    case 0x00: // command register (16-bit) (R/W)
+      if (value & 0xFF00)
+        BX_ERROR(("write to command register with bits 15:8 not zero: 0x%04x", value));
+
+      BX_USB_THIS hub[0].usb_command.max_packet_size = (value & 0x80) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.configured = (value & 0x40) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.debug = (value & 0x20) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.resume = (value & 0x10) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.suspend = (value & 0x08) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.reset = (value & 0x04) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.host_reset = (value & 0x02) ? 1: 0;
+      BX_USB_THIS hub[0].usb_command.schedule = (value & 0x01) ? 1: 0;
+
+      // If software set the reset bit, we need to set reset bit of each port for 10ms.
+      if (BX_USB_THIS hub[0].usb_command.reset)
+        BX_USB_THIS global_reset = 10;
+
+      // If host_reset then reset all registers, etc.
+      if (BX_USB_THIS hub[0].usb_command.host_reset)
+        BX_USB_THIS reset(0);
+
+      // If Run/Stop, identify in log and ignore
+      if (BX_USB_THIS hub[0].usb_command.schedule)
+        BX_INFO(("Software set Schedule bit in Command register"));
+
+      // If Debug mode set, panic.  Not implemented
+      if (BX_USB_THIS hub[0].usb_command.debug)
+        BX_PANIC(("Software set DEBUG bit in Command register. Not implemented"));
+
+      break;
+
+    case 0x02: // status register (16-bit) (R/WC)
+      if (value & 0xFFC0)
+        BX_ERROR(("write to status register with bits 15:6 not zero: 0x%04x", value));
+
+      BX_USB_THIS hub[0].usb_status.host_halted = (value & 0x20) ? 0: BX_USB_THIS hub[0].usb_status.host_halted;
+      BX_USB_THIS hub[0].usb_status.host_error = (value & 0x10) ? 0: BX_USB_THIS hub[0].usb_status.host_error;
+      BX_USB_THIS hub[0].usb_status.pci_error = (value & 0x08) ? 0: BX_USB_THIS hub[0].usb_status.pci_error;
+      BX_USB_THIS hub[0].usb_status.resume = (value & 0x04) ? 0: BX_USB_THIS hub[0].usb_status.resume;
+      BX_USB_THIS hub[0].usb_status.error_interrupt = (value & 0x02) ? 0: BX_USB_THIS hub[0].usb_status.error_interrupt;
+      BX_USB_THIS hub[0].usb_status.interrupt = (value & 0x01) ? 0: BX_USB_THIS hub[0].usb_status.interrupt;
+      break;
+
+    case 0x04: // interrupt enable register (16-bit)
+      if (value & 0xFFF0)
+        BX_ERROR(("write to interrupt enable register with bits 15:4 not zero: 0x%04x", value));
+
+      BX_USB_THIS hub[0].usb_enable.short_packet  = (value & 0x08) ? 1: 0;
+      BX_USB_THIS hub[0].usb_enable.on_complete  = (value & 0x04) ? 1: 0;
+      BX_USB_THIS hub[0].usb_enable.resume  = (value & 0x02) ? 1: 0;
+      BX_USB_THIS hub[0].usb_enable.timeout_crc = (value & 0x01) ? 1: 0;
+
+      // For now, we will just ignore these being set since we never raise the IRQ
+
+      break;
+
+    case 0x06: // frame number register (16-bit)
+      if (value & 0xF800)
+        BX_ERROR(("write to frame number register with bits 15:11 not zero: 0x%04x", value));
+
+      if (BX_USB_THIS hub[0].usb_status.host_halted)
+        BX_USB_THIS hub[0].usb_frame_num.frame_num = value;
+      else
+        // ignored by the hardward, but lets report it anyway
+        BX_ERROR(("write to frame number register with STATUS.HALTED == 0"));
+
+      break;
+
+    case 0x08: // frame base register (32-bit)
+      if (value & 0xFFF)
+        BX_PANIC(("write to frame base register with bits 11:0 not zero: 0x%08x", value));
+
+      BX_USB_THIS hub[0].usb_frame_base.frame_base = value;
+      break;
+
+    case 0x0C: // start of Frame Modify register (8-bit)
+      if (value & 0x80)
+        BX_ERROR(("write to SOF Modify register with bit 7 not zero: 0x%04x", value));
+
+       BX_USB_THIS hub[0].usb_sof.sof_timing = value;
+       break;
+
+    case 0x10: // port0
+    case 0x12: // port1
+      port = (offset & 0x0F) >> 1;
+      if (port < USB_NUM_PORTS) {
+        if (value & ((1<<5) | (1<<4) | (1<<0)))
+          BX_PANIC(("write to one or more read-only bits in port%d register: 0x%04x", port, value));
+        if (!(value & (1<<7)))
+          BX_ERROR(("write to port%d register bit 7 = 0", port));
+        if (value & (1<<8))
+          BX_INFO(("write to bit 8 in port%d register ignored", port));
+        if (value & (1<<2))
+          BX_INFO(("port%d enabled ignored.  Not implemented", port));
+        if ((value & (1<<12)) && BX_USB_THIS hub[0].usb_command.suspend)
+          BX_ERROR(("write to port%d register bit 12 when in Global-Suspend", port));
+
+        BX_USB_THIS hub[0].usb_port[port].suspend = (value & (1<<12)) ? 1 : 0;
+        BX_USB_THIS hub[0].usb_port[port].reset = (value & (1<<9)) ? 1 : 0;
+        BX_USB_THIS hub[0].usb_port[port].resume = (value & (1<<6)) ? 1 : 0;
+        BX_USB_THIS hub[0].usb_port[port].able_changed = (value & (1<<3)) ? 0 : BX_USB_THIS hub[0].usb_port[0].able_changed;
+        BX_USB_THIS hub[0].usb_port[port].enabled = (value & (1<<2)) ? 1 : 0;
+        BX_USB_THIS hub[0].usb_port[port].connect_changed = (value & (1<<1)) ? 0 : BX_USB_THIS hub[0].usb_port[0].connect_changed;
+        break;
+      }
+      // else fall through to default
+
+    default:
+      BX_PANIC(("unsupported io write to address=0x%04x!", (unsigned) address));
+      break;
+  }
+}
+
+void bx_pciusb_c::usb_timer_handler(void *this_ptr)
+{
+  bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+  class_ptr->usb_timer();
+}
+
+// Called once every 1ms
+void bx_pciusb_c::usb_timer(void)
+{
+  int i;
+
+  // The Frame Number Register is incremented every 1ms  ?????????
+  // Needs more work and investigation on this.
+  BX_USB_THIS hub[0].usb_frame_num.frame_num++;
+  BX_USB_THIS hub[0].usb_frame_num.frame_num &= (1024-1);
+
+  // If the "global reset" bit was set by software, we need
+  // to set the reset bit in each "active" port for 10ms
+  if (BX_USB_THIS global_reset) {
+    for (i=0; i<USB_NUM_PORTS; i++) {
+      BX_USB_THIS hub[0].usb_port[i].able_changed = 0;
+      BX_USB_THIS hub[0].usb_port[i].connect_changed = 0;
+      BX_USB_THIS hub[0].usb_port[i].enabled = 0;
+      BX_USB_THIS hub[0].usb_port[i].line_dminus = 0;
+      BX_USB_THIS hub[0].usb_port[i].line_dplus = 0;
+      BX_USB_THIS hub[0].usb_port[i].low_speed = 0;
+      BX_USB_THIS hub[0].usb_port[i].reset = 1;
+      BX_USB_THIS hub[0].usb_port[i].resume = 0;
+      BX_USB_THIS hub[0].usb_port[i].status = 0;
+      BX_USB_THIS hub[0].usb_port[i].suspend = 0;
+    }
+    BX_USB_THIS global_reset--;
+  } else {
+    for (i=0; i<USB_NUM_PORTS; i++)
+      BX_USB_THIS hub[0].usb_port[i].reset = 0;
+  }
+
+  // If command.schedule = 0, then we need to set Status.Halted
+  if (!BX_USB_THIS hub[0].usb_command.schedule)
+    BX_USB_THIS hub[0].usb_status.host_halted = 1;
+
+
+  // TODO:
+  //  If ins Global_Suspend mode and any of usb_port[i] bits 6,3, or 1 are set,
+  //    we need to issue a Global_Resume (set the global resume bit).
+  //    However, since we don't do anything, let's not.
+
+}
+  
+  // static pci configuration space read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pciusb_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+  bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+  return class_ptr->pci_read(address, io_len);
+}
+
+
+  Bit32u
+bx_pciusb_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+
+  Bit32u value = 0;
+
+  if (io_len > 4 || io_len == 0) {
+    BX_ERROR(("Experimental USB PCI read register 0x%02x, len=%u !",
+             (unsigned) address, (unsigned) io_len));
+    return 0xffffffff;
+  }
+
+  const char* pszName = "                  ";
+  switch (address) {
+    case 0x00: if (io_len == 2) {
+                 pszName = "(vendor id)       ";
+               } else if (io_len == 4) {
+                 pszName = "(vendor + device) ";
+               }
+      break;
+    case 0x04: if (io_len == 2) {
+                 pszName = "(command)         ";
+               } else if (io_len == 4) {
+                 pszName = "(command+status)  ";
+               }
+      break;
+    case 0x08: if (io_len == 1) {
+                 pszName = "(revision id)     ";
+               } else if (io_len == 4) {
+                 pszName = "(rev.+class code) ";
+               }
+      break;
+    case 0x0c: pszName = "(cache line size) "; break;
+    case 0x20: pszName = "(base address)    "; break;
+    case 0x28: pszName = "(cardbus cis)     "; break;
+    case 0x2c: pszName = "(subsys. vendor+) "; break;
+    case 0x30: pszName = "(rom base)        "; break;
+    case 0x3c: pszName = "(interrupt line+) "; break;
+    case 0x3d: pszName = "(interrupt pin)   "; break;
+  }
+
+  // This odd code is to display only what bytes actually were read.
+  char szTmp[9];
+  char szTmp2[3];
+  szTmp[0] = '\0';
+  szTmp2[0] = '\0';
+  for (unsigned i=0; i<io_len; i++) {
+    value |= (BX_USB_THIS hub[0].pci_conf[address+i] << (i*8));
+    sprintf(szTmp2, "%02x", (BX_USB_THIS hub[0].pci_conf[address+i]));
+    strrev(szTmp2);
+    strcat(szTmp, szTmp2);
+  }
+  strrev(szTmp);
+  BX_DEBUG(("Experimental USB PCI read register 0x%02x %svalue 0x%s",
+            address, pszName, szTmp));
+  return value;
+}
+
+
+  // static pci configuration space write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pciusb_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIUSB_SMF
+  bx_pciusb_c *class_ptr = (bx_pciusb_c *) this_ptr;
+
+  class_ptr->pci_write(address, value, io_len);
+}
+
+  void
+bx_pciusb_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIUSB_SMF
+
+  if (io_len > 4 || io_len == 0) {
+    BX_ERROR(("Experimental USB PCI write register 0x%02x, len=%u !",
+             (unsigned) address, (unsigned) io_len));
+    return;
+  }
+
+  // This odd code is to display only what bytes actually were written.
+  char szTmp[9];
+  char szTmp2[3];
+  szTmp[0] = '\0';
+  szTmp2[0] = '\0';
+  for (unsigned i=0; i<io_len; i++) {
+    const Bit8u value8 = (value >> (i*8)) & 0xFF;
+    switch (address+i) {
+      case 0x20: // Base address
+        BX_USB_THIS hub[0].pci_conf[address+i] = (value8 & 0xe0) | 0x01;
+        sprintf(szTmp2, "%02x", (value8 & 0xe0) | 0x01);
+        break;
+      case 0x10: // Reserved
+      case 0x11: //
+      case 0x12: //
+      case 0x13: //
+      case 0x14: //
+      case 0x15: //
+      case 0x16: //
+      case 0x17: //
+      case 0x18: //
+      case 0x19: //
+      case 0x1a: //
+      case 0x1b: //
+      case 0x1c: //
+      case 0x1d: //
+      case 0x1e: //
+      case 0x1f: //
+      case 0x22: // Always 0
+      case 0x23: //
+      case 0x24: // Reserved
+      case 0x25: //
+      case 0x26: //
+      case 0x27: //
+      case 0x30: // Oh, no, you're not writing to rom_base!
+      case 0x31: //
+      case 0x32: //
+      case 0x33: //
+      case 0x3d: //
+      case 0x05: // disallowing write to command hi-byte
+      case 0x06: // disallowing write to status lo-byte (is that expected?)
+        strcpy(szTmp2, "..");
+        break;
+      default:
+        BX_USB_THIS hub[0].pci_conf[address+i] = value8;
+        sprintf(szTmp2, "%02x", value8);
+    }
+    strrev(szTmp2);
+    strcat(szTmp, szTmp2);
+  }
+  strrev(szTmp);
+  BX_DEBUG(("Experimental USB PCI write register 0x%02x value 0x%s", address, szTmp));
+}
+
+#endif // BX_PCI_SUPPORT && BX_PCI_USB_SUPPORT
diff --git a/tools/ioemu/iodev/pciusb.h b/tools/ioemu/iodev/pciusb.h
new file mode 100644 (file)
index 0000000..be2532c
--- /dev/null
@@ -0,0 +1,195 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pciusb.h,v 1.1 2003/01/28 16:58:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2003  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// Benjamin D Lunt (fys@cybertrails.com) coded most of this usb emulation.
+//  I hope to add to this code to make it more functionable.
+//
+
+#if BX_USE_PCIUSB_SMF
+#  define BX_USB_THIS theUSBDevice->
+#else
+#  define BX_USB_THIS this->
+#endif
+
+#define BX_USB_MAXDEV   1
+#define BX_USB_CONFDEV  1   /* only 1 USB hub currently */
+
+#define USB_NUM_PORTS   2 /* UHCI supports 2 ports per root hub */
+
+typedef struct {
+
+  Bit16u base_ioaddr;
+  Bit8u  irq;
+  int    timer_index;
+
+  // Registers
+  // Base + 0x00  Command register
+  // Base + 0x02  Status register
+  // Base + 0x04  Interrupt Enable register
+  // Base + 0x06  Frame Number register
+  // Base + 0x08  Frame Base Register (32-bit)
+  // Base + 0x0C  Start of Frame Modify register
+  // Base + 0x0D
+  // Base + 0x0E
+  // Base + 0x0F
+  // Base + 0x10  Eight(?) 16-bit ports (one for each port on hub)
+
+  // Bit reps of registers above
+  // Command Register
+  //  Bits 15-8 are reserved
+  //  Bit 7 = Maximum packet size
+  //  Bit 6 = Host Controller has been configured (set by software)
+  //  Bit 5 = software debug mode
+  //  Bit 4 = force global resume
+  //  Bit 3 = enter global suspend mode
+  //  Bit 2 = global reset
+  //  Bit 1 = host controller reset
+  //  Bit 0 = run/stop schedule
+  struct {
+    bx_bool max_packet_size; //(bit 7) 0 = 32 bytes, 1 = 64 bytes
+    bx_bool configured;      //(bit 6)
+    bx_bool debug;           //(bit 5)
+    bx_bool resume;          //(bit 4)
+    bx_bool suspend;         //(bit 3)
+    bx_bool reset;           //(bit 2)
+    bx_bool host_reset;      //(bit 1)
+    bx_bool schedule;        //(bit 0) 0 = Stop, 1 = Run
+  } usb_command;
+
+  // Status Register
+  //  Bits 15-6 are reserved
+  //  Bit 5 = Host controller halted
+  //  Bit 4 = Host controller process error
+  //  Bit 3 = PCI Bus error
+  //  Bit 2 = resume received
+  //  Bit 1 = USB error interrupt
+  //  Bit 0 = USB interrupt
+  struct {
+    bx_bool host_halted;     //(bit 5)
+    bx_bool host_error;      //(bit 4)
+    bx_bool pci_error;       //(bit 3)
+    bx_bool resume;          //(bit 2)
+    bx_bool error_interrupt; //(bit 1)
+    bx_bool interrupt;       //(bit 0)
+  } usb_status;
+
+  // Interrupt Enable Register
+  //  Bits 15-4 are reserved
+  //  Bit 3 = enable short packet interrupts
+  //  Bit 2 = enable interrupt On Complete
+  //  Bit 1 = enable resume
+  //  Bit 0 = enable timeout/crc
+  struct {
+    bx_bool short_packet; //(bit 3)
+    bx_bool on_complete;  //(bit 2)
+    bx_bool resume;       //(bit 1)
+    bx_bool timeout_crc;  //(bit 0)
+  } usb_enable;
+
+  // Frame Number Register
+  //  Bits 15-11 are reserved
+  //  Bits 10-0  Frame List Current Index/Frame Number
+  struct {
+    Bit16u frame_num;
+  } usb_frame_num;
+
+  // Frame List Base Address Register
+  //  Bits 31-12  Base
+  //  Bits 11-0   *must* be zeros when written to
+  struct {
+    Bit32u frame_base;
+  } usb_frame_base;
+
+  // Start of Frame Modify Register
+  //  Bit    7 reserved
+  //  Bits 6-0 SOF timing value (default 64)
+  // SOF cycle time equals 11936+timing value
+  struct {
+    Bit8u sof_timing;
+  } usb_sof;
+
+  // Port Register (0-1)
+  //  Bits 15-13  are reserved
+  //  Bit     12  suspend port
+  //  Bit  11-10  are reserved
+  //  Bit      9  port in reset state
+  //  Bit      8  low-speed device is attached (read-only)
+  //  Bit      7  reserved
+  //  Bit      6  resume detected (read-only)
+  //  Bit      5  line-status D+ (read-only)
+  //  Bit      4  line-status D- (read-only)
+  //  Bit      3  port enabled/disable status has changed
+  //               (write 1 to this bit to clear it)
+  //  Bit      2  port is enabled
+  //  Bit      1  connect status has changed
+  //               (write 1 to this bit to clear it)
+  //  Bit      0  current connect status (read-only)
+  //  Can only write in WORD sizes (Read in byte sizes???)
+  struct {
+    bx_bool suspend;
+    bx_bool reset;
+    bx_bool low_speed;
+    bx_bool resume;
+    bx_bool line_dplus;
+    bx_bool line_dminus;
+    bx_bool able_changed;
+    bx_bool enabled;
+    bx_bool connect_changed;
+    bx_bool status;
+  } usb_port[USB_NUM_PORTS];
+
+  Bit8u pci_conf[256];
+
+} bx_usb_t;
+
+
+class bx_pciusb_c : public bx_devmodel_c
+{
+public:
+  bx_pciusb_c(void);
+  ~bx_pciusb_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+
+  bx_usb_t hub[BX_USB_MAXDEV];
+  Bit8u  global_reset;
+
+  static void usb_timer_handler(void *);
+  void usb_timer(void);
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+  static void   pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PCIUSB_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+  Bit32u pci_read(Bit8u address, unsigned io_len);
+  void   pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+};
diff --git a/tools/ioemu/iodev/pcivga.cc b/tools/ioemu/iodev/pcivga.cc
new file mode 100644 (file)
index 0000000..4d999be
--- /dev/null
@@ -0,0 +1,248 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pcivga.cc,v 1.2 2003/01/23 19:31:28 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002,2003 Mike Nordell
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+//
+// Experimental PCI VGA adapter
+//
+
+// Note: This "driver" was created for the SOLE PURPOSE of getting BeOS
+// to boot. It currently does NOTHING more than presenting a generic VGA
+// device on the PCI bus. ALL gfx in/out-put is still handled by the VGA code.
+// Furthermore, almost all of the PCI registers are currently acting like RAM.
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if BX_PCI_SUPPORT && BX_PCI_VGA_SUPPORT
+
+#define LOG_THIS thePciVgaAdapter->
+
+bx_pcivga_c* thePciVgaAdapter = 0;
+
+  int
+libpcivga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  thePciVgaAdapter = new bx_pcivga_c ();
+  bx_devices.pluginPciVgaAdapter = thePciVgaAdapter;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciVgaAdapter, BX_PLUGIN_PCIVGA);
+  return 0; // Success
+}
+
+  void
+libpcivga_LTX_plugin_fini(void)
+{
+}
+
+
+bx_pcivga_c::bx_pcivga_c(void)
+{
+  put("PCIVGA");
+  settype(PCIVGALOG);
+}
+
+bx_pcivga_c::~bx_pcivga_c(void)
+{
+  // nothing for now
+  BX_DEBUG(("Exit."));
+}
+
+
+  void
+bx_pcivga_c::init(void)
+{
+  // called once when bochs initializes
+
+  DEV_register_pci_handlers(this,
+                            pci_read_handler,
+                            pci_write_handler,
+                            BX_PCI_DEVICE(2,0),
+                            "Experimental PCI VGA");
+
+  for (unsigned i=0; i<256; i++) {
+    BX_PCIVGA_THIS s.pci_conf[i] = 0x0;
+  }
+
+  // readonly registers
+  static const struct init_vals_t {
+    unsigned      addr;
+    unsigned char val;
+  } init_vals[] = {
+    // Note that the values for vendor and device id are selected at random!
+    // There might actually be "real" values for "experimental" vendor and
+    // device that should be used!
+    { 0x00, 0x34 }, { 0x01, 0x12 }, // 0x1234 - experimental vendor
+    { 0x02, 0x11 }, { 0x03, 0x11 }, // 0x1111 - experimental device
+    { 0x0a, 0x00 },                 // class_sub  VGA controller
+    { 0x0b, 0x03 },                 // class_base display
+    { 0x0e, 0x00 }                  // header_type_generic
+  };
+  for (unsigned i = 0; i < sizeof(init_vals) / sizeof(*init_vals); ++i) {
+    BX_PCIVGA_THIS s.pci_conf[init_vals[i].addr] = init_vals[i].val;
+  }
+}
+
+  void
+bx_pcivga_c::reset(unsigned type)
+{
+  static const struct reset_vals_t {
+    unsigned      addr;
+    unsigned char val;
+  } reset_vals[] = {
+      { 0x04, 0x01 }, { 0x05, 0x00 },  // command_io
+      { 0x06, 0x00 }, { 0x07, 0x02 }   // status_devsel_medium
+  };
+  for (unsigned i = 0; i < sizeof(reset_vals) / sizeof(*reset_vals); ++i) {
+      BX_PCIVGA_THIS s.pci_conf[reset_vals[i].addr] = reset_vals[i].val;
+  }
+}
+
+
+  // static pci configuration space read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pcivga_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
+{
+#if !BX_USE_PCIVGA_SMF
+  bx_pcivga_c *class_ptr = (bx_pcivga_c *) this_ptr;
+
+  return class_ptr->pci_read(address, io_len);
+}
+
+
+  Bit32u
+bx_pcivga_c::pci_read(Bit8u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIVGA_SMF
+
+  Bit32u value = 0;
+
+  if (io_len > 4 || io_len == 0) {
+    BX_DEBUG(("Experimental PCIVGA read register 0x%02x, len=%u !",
+             (unsigned) address, (unsigned) io_len));
+    return 0xffffffff;
+  }
+
+  const char* pszName = "                  ";
+  switch (address) {
+    case 0x00: if (io_len == 2) {
+                 pszName = "(vendor id)       ";
+               } else if (io_len == 4) {
+                 pszName = "(vendor + device) ";
+               }
+      break;
+    case 0x04: if (io_len == 2) {
+                 pszName = "(command)         ";
+               } else if (io_len == 4) {
+                 pszName = "(command+status)  ";
+               }
+      break;
+    case 0x08: if (io_len == 1) {
+                 pszName = "(revision id)     ";
+               } else if (io_len == 4) {
+                 pszName = "(rev.+class code) ";
+               }
+      break;
+    case 0x0c: pszName = "(cache line size) "; break;
+    case 0x28: pszName = "(cardbus cis)     "; break;
+    case 0x2c: pszName = "(subsys. vendor+) "; break;
+    case 0x30: pszName = "(rom base)        "; break;
+    case 0x3c: pszName = "(interrupt line+) "; break;
+    case 0x3d: pszName = "(interrupt pin)   "; break;
+  }
+
+  // This odd code is to display only what bytes actually were read.
+  char szTmp[9];
+  char szTmp2[3];
+  szTmp[0] = '\0';
+  szTmp2[0] = '\0';
+  for (unsigned i=0; i<io_len; i++) {
+    value |= (BX_PCIVGA_THIS s.pci_conf[address+i] << (i*8));
+
+    sprintf(szTmp2, "%02x", (BX_PCIVGA_THIS s.pci_conf[address+i]));
+    strrev(szTmp2);
+    strcat(szTmp, szTmp2);
+  }
+  strrev(szTmp);
+  BX_DEBUG(("Experimental PCIVGA  read register 0x%02x %svalue 0x%s",
+            address, pszName, szTmp));
+  return value;
+}
+
+
+  // static pci configuration space write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pcivga_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PCIVGA_SMF
+  bx_pcivga_c *class_ptr = (bx_pcivga_c *) this_ptr;
+
+  class_ptr->pci_write(address, value, io_len);
+}
+
+  void
+bx_pcivga_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PCIVGA_SMF
+
+  if (io_len > 4 || io_len == 0) {
+    BX_DEBUG(("Experimental PCIVGA write register 0x%02x, len=%u !",
+             (unsigned) address, (unsigned) io_len));
+    return;
+  }
+
+  // This odd code is to display only what bytes actually were written.
+  char szTmp[9];
+  char szTmp2[3];
+  szTmp[0] = '\0';
+  szTmp2[0] = '\0';
+  for (unsigned i=0; i<io_len; i++) {
+    const Bit8u value8 = (value >> (i*8)) & 0xFF;
+    switch (address+i) {
+      case 0x30: // Oh, no, you're not writing to rom_base!
+      case 0x31: //
+      case 0x32: //
+      case 0x33: //
+      case 0x04: // disallowing write to command
+      case 0x06: // disallowing write to status lo-byte (is that expected?)
+        strcpy(szTmp2, "..");
+        break;
+      default:
+        BX_PCIVGA_THIS s.pci_conf[address+i] = value8;
+        sprintf(szTmp2, "%02x", value8);
+    }
+    strrev(szTmp2);
+    strcat(szTmp, szTmp2);
+  }
+  strrev(szTmp);
+  BX_DEBUG(("Experimental PCIVGA write register 0x%02x value 0x%s", address, szTmp));
+}
+
+#endif // BX_PCI_SUPPORT && BX_PCI_VGA_SUPPORT
diff --git a/tools/ioemu/iodev/pcivga.h b/tools/ioemu/iodev/pcivga.h
new file mode 100644 (file)
index 0000000..15bd986
--- /dev/null
@@ -0,0 +1,48 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pcivga.h,v 1.3 2003/01/27 21:11:55 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002,2003  Mike Nordell
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#if BX_USE_PCIVGA_SMF
+#  define BX_PCIVGA_THIS thePciVgaAdapter->
+#else
+#  define BX_PCIVGA_THIS this->
+#endif
+
+
+class bx_pcivga_c : public bx_devmodel_c
+{
+public:
+  bx_pcivga_c(void);
+  ~bx_pcivga_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+
+private:
+
+  struct {
+    Bit8u pci_conf[256];
+  } s;
+
+  static Bit32u pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len);
+  static void   pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PCIVGA_SMF
+  Bit32u pci_read(Bit8u address, unsigned io_len);
+  void   pci_write(Bit8u address, Bit32u value, unsigned io_len);
+#endif
+};
diff --git a/tools/ioemu/iodev/pic.cc b/tools/ioemu/iodev/pic.cc
new file mode 100644 (file)
index 0000000..d79c376
--- /dev/null
@@ -0,0 +1,872 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pic.cc,v 1.33 2003/08/05 09:19:36 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS thePic->
+
+
+
+bx_pic_c *thePic = NULL;
+
+  int
+libpic_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  thePic = new bx_pic_c ();
+  bx_devices.pluginPicDevice = thePic;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePic, BX_PLUGIN_PIC);
+  return(0); // Success
+}
+
+  void
+libpic_LTX_plugin_fini(void)
+{
+}
+
+
+bx_pic_c::bx_pic_c(void)
+{
+  put("PIC");
+  settype(PICLOG);
+}
+
+bx_pic_c::~bx_pic_c(void)
+{
+  // nothing for now
+}
+
+
+  void
+bx_pic_c::init(void)
+{
+  /* 8259 PIC (Programmable Interrupt Controller) */
+  DEV_register_ioread_handler(this, read_handler, 0x0020, "8259 PIC", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0021, "8259 PIC", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x00A0, "8259 PIC", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x00A1, "8259 PIC", 1);
+
+  DEV_register_iowrite_handler(this, write_handler, 0x0020, "8259 PIC", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0021, "8259 PIC", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x00A0, "8259 PIC", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x00A1, "8259 PIC", 1);
+
+
+  BX_PIC_THIS s.master_pic.single_PIC = 0;
+  BX_PIC_THIS s.master_pic.interrupt_offset = 0x08; /* IRQ0 = INT 0x08 */
+  /* slave PIC connected to IRQ2 of master */
+  BX_PIC_THIS s.master_pic.u.slave_connect_mask = 0x04;
+  BX_PIC_THIS s.master_pic.sfnm = 0; /* normal nested mode */
+  BX_PIC_THIS s.master_pic.buffered_mode = 0; /* unbuffered mode */
+  BX_PIC_THIS s.master_pic.master_slave  = 0; /* no meaning, buffered_mode=0 */
+  BX_PIC_THIS s.master_pic.auto_eoi      = 0; /* manual EOI from CPU */
+  BX_PIC_THIS s.master_pic.imr           = 0xFF; /* all IRQ's initially masked */
+  BX_PIC_THIS s.master_pic.isr           = 0x00; /* no IRQ's in service */
+  BX_PIC_THIS s.master_pic.irr           = 0x00; /* no IRQ's requested */
+  BX_PIC_THIS s.master_pic.read_reg_select = 0; /* IRR */
+  BX_PIC_THIS s.master_pic.irq = 0;
+  BX_PIC_THIS s.master_pic.INT = 0;
+  BX_PIC_THIS s.master_pic.init.in_init = 0;
+  BX_PIC_THIS s.master_pic.init.requires_4 = 0;
+  BX_PIC_THIS s.master_pic.init.byte_expected = 0;
+  BX_PIC_THIS s.master_pic.special_mask = 0;
+  BX_PIC_THIS s.master_pic.lowest_priority = 7;
+  BX_PIC_THIS s.master_pic.polled = 0;
+  BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
+
+  BX_PIC_THIS s.slave_pic.single_PIC = 0;
+  BX_PIC_THIS s.slave_pic.interrupt_offset = 0x70; /* IRQ8 = INT 0x70 */
+  BX_PIC_THIS s.slave_pic.u.slave_id = 0x02; /* slave PIC connected to IRQ2 of master */
+  BX_PIC_THIS s.slave_pic.sfnm       = 0; /* normal nested mode */
+  BX_PIC_THIS s.slave_pic.buffered_mode = 0; /* unbuffered mode */
+  BX_PIC_THIS s.slave_pic.master_slave  = 0; /* no meaning, buffered_mode=0 */
+  BX_PIC_THIS s.slave_pic.auto_eoi      = 0; /* manual EOI from CPU */
+  BX_PIC_THIS s.slave_pic.imr           = 0xFF; /* all IRQ's initially masked */
+  BX_PIC_THIS s.slave_pic.isr           = 0x00; /* no IRQ's in service */
+  BX_PIC_THIS s.slave_pic.irr           = 0x00; /* no IRQ's requested */
+  BX_PIC_THIS s.slave_pic.read_reg_select = 0; /* IRR */
+  BX_PIC_THIS s.slave_pic.irq = 0;
+  BX_PIC_THIS s.slave_pic.INT = 0;
+  BX_PIC_THIS s.slave_pic.init.in_init = 0;
+  BX_PIC_THIS s.slave_pic.init.requires_4 = 0;
+  BX_PIC_THIS s.slave_pic.init.byte_expected = 0;
+  BX_PIC_THIS s.slave_pic.special_mask = 0;
+  BX_PIC_THIS s.slave_pic.lowest_priority = 7;
+  BX_PIC_THIS s.slave_pic.polled = 0;
+  BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
+
+  for (unsigned i=0; i<8; i++) { /* all IRQ lines low */
+    BX_PIC_THIS s.master_pic.IRQ_line[i] = 0;
+    BX_PIC_THIS s.slave_pic.IRQ_line[i] = 0;
+  }
+}
+
+  void
+bx_pic_c::reset(unsigned type)
+{
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pic_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PIC_SMF
+  bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+
+  Bit32u
+bx_pic_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PIC_SMF
+
+  BX_DEBUG(("IO read from %04x", (unsigned) address));
+
+  /*
+   8259A PIC
+   */
+
+  if((address == 0x20 || address == 0x21) && BX_PIC_THIS s.master_pic.polled) {
+    // In polled mode. Treat this as an interrupt acknowledge
+    clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
+    BX_PIC_THIS s.master_pic.polled = 0;
+    service_master_pic();
+    return io_len==1?BX_PIC_THIS s.master_pic.irq:(BX_PIC_THIS s.master_pic.irq)<<8|(BX_PIC_THIS s.master_pic.irq);  // Return the current irq requested
+  }
+
+  if((address == 0xa0 || address == 0xa1) && BX_PIC_THIS s.slave_pic.polled) {
+    // In polled mode. Treat this as an interrupt acknowledge
+    clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
+    BX_PIC_THIS s.slave_pic.polled = 0;
+    service_slave_pic();
+    return io_len==1?BX_PIC_THIS s.slave_pic.irq:(BX_PIC_THIS s.slave_pic.irq)<<8|(BX_PIC_THIS s.slave_pic.irq);  // Return the current irq requested
+  }
+
+
+  switch (address) {
+    case 0x20:
+      if (BX_PIC_THIS s.master_pic.read_reg_select) { /* ISR */
+        BX_DEBUG(("read master ISR = %02x",
+                  (unsigned) BX_PIC_THIS s.master_pic.isr));
+       return(BX_PIC_THIS s.master_pic.isr);
+       }
+      else { /* IRR */
+        BX_DEBUG(("read master IRR = %02x",
+                 (unsigned) BX_PIC_THIS s.master_pic.irr));
+       return(BX_PIC_THIS s.master_pic.irr);
+       }
+      break;
+    case 0x21:
+      BX_DEBUG(("read master IMR = %02x",
+               (unsigned) BX_PIC_THIS s.master_pic.imr));
+      return(BX_PIC_THIS s.master_pic.imr);
+      break;
+    case 0xA0:
+      if (BX_PIC_THIS s.slave_pic.read_reg_select) { /* ISR */
+        BX_DEBUG(("read slave ISR = %02x",
+                  (unsigned) BX_PIC_THIS s.slave_pic.isr));
+       return(BX_PIC_THIS s.slave_pic.isr);
+       }
+      else { /* IRR */
+        BX_DEBUG(("read slave IRR = %02x",
+                  (unsigned) BX_PIC_THIS s.slave_pic.irr));
+       return(BX_PIC_THIS s.slave_pic.irr);
+       }
+      break;
+    case 0xA1:
+      BX_DEBUG(("read slave IMR = %02x",
+                (unsigned) BX_PIC_THIS s.slave_pic.imr));
+      return(BX_PIC_THIS s.slave_pic.imr);
+      break;
+    }
+
+  BX_PANIC(("io read to address %04x", (unsigned) address));
+  return(0); /* default if not found above */
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pic_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_PIC_SMF
+  bx_pic_c *class_ptr = (bx_pic_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_pic_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif // !BX_USE_PIC_SMF
+
+  BX_DEBUG(("IO write to %04x = %02x", (unsigned) address, (unsigned) value));
+
+  /*
+   8259A PIC
+   */
+
+  switch (address) {
+    case 0x20:
+      if (value & 0x10) { /* initialization command 1 */
+        BX_DEBUG(("master: init command 1 found"));
+        BX_DEBUG(("        requires 4 = %u", (unsigned) (value & 0x01) ));
+        BX_DEBUG(("        cascade mode: [0=cascade,1=single] %u",
+                  (unsigned) ((value & 0x02) >> 1)));
+        BX_PIC_THIS s.master_pic.init.in_init = 1;
+        BX_PIC_THIS s.master_pic.init.requires_4 = (value & 0x01);
+        BX_PIC_THIS s.master_pic.init.byte_expected = 2; /* operation command 2 */
+        BX_PIC_THIS s.master_pic.imr           = 0x00; /* clear the irq mask register */
+        BX_PIC_THIS s.master_pic.isr           = 0x00; /* no IRQ's in service */
+        BX_PIC_THIS s.master_pic.irr           = 0x00; /* no IRQ's requested */
+        BX_PIC_THIS s.master_pic.lowest_priority = 7;
+        BX_PIC_THIS s.master_pic.INT = 0; /* reprogramming clears previous INTR request */
+        BX_PIC_THIS s.master_pic.auto_eoi = 0;
+        BX_PIC_THIS s.master_pic.rotate_on_autoeoi = 0;
+        if (value & 0x02)
+          BX_PANIC(("master: ICW1: single mode not supported"));
+        if (value & 0x08) {
+          BX_PANIC(("master: ICW1: level sensitive mode not supported"));
+         }
+       else {
+          BX_DEBUG(("master: ICW1: edge triggered mode selected"));
+         }
+        BX_SET_INTR(0);
+        return;
+        }
+
+      if ( (value & 0x18) == 0x08 ) { /* OCW3 */
+        Bit8u special_mask, poll, read_op;
+
+        special_mask = (value & 0x60) >> 5;
+        poll         = (value & 0x04) >> 2;
+        read_op      = (value & 0x03);
+        if (poll) {
+          BX_PIC_THIS s.master_pic.polled = 1;
+          return;
+        }
+        if (read_op == 0x02) /* read IRR */
+         BX_PIC_THIS s.master_pic.read_reg_select = 0;
+        else if (read_op == 0x03) /* read ISR */
+         BX_PIC_THIS s.master_pic.read_reg_select = 1;
+        if (special_mask == 0x02) { /* cancel special mask */
+          BX_PIC_THIS s.master_pic.special_mask = 0;
+          }
+        else if (special_mask == 0x03) { /* set specific mask */
+          BX_PIC_THIS s.master_pic.special_mask = 1;
+          service_master_pic();
+          }
+        return;
+        }
+
+      /* OCW2 */
+      switch (value) {
+        case 0x00: // Rotate in auto eoi mode clear
+        case 0x80: // Rotate in auto eoi mode set
+          BX_PIC_THIS s.master_pic.rotate_on_autoeoi = (value != 0);
+          break;
+       case 0x0A: /* select read interrupt request register */
+         BX_PIC_THIS s.master_pic.read_reg_select = 0;
+         break;
+       case 0x0B: /* select read interrupt in-service register */
+         BX_PIC_THIS s.master_pic.read_reg_select = 1;
+         break;
+
+        case 0xA0: // Rotate on non-specific end of interrupt
+        case 0x20: /* end of interrupt command */
+
+          clear_highest_interrupt(& BX_PIC_THIS s.master_pic);
+
+          if(value == 0xA0) {// Rotate in Auto-EOI mode
+            BX_PIC_THIS s.master_pic.lowest_priority ++;
+            if(BX_PIC_THIS s.master_pic.lowest_priority > 7)
+              BX_PIC_THIS s.master_pic.lowest_priority = 0;
+          }
+
+          service_master_pic();
+          break;
+
+        case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
+          BX_INFO(("IRQ no-op"));
+          break;
+
+        case 0x60: /* specific EOI 0 */
+        case 0x61: /* specific EOI 1 */
+        case 0x62: /* specific EOI 2 */
+        case 0x63: /* specific EOI 3 */
+        case 0x64: /* specific EOI 4 */
+        case 0x65: /* specific EOI 5 */
+        case 0x66: /* specific EOI 6 */
+        case 0x67: /* specific EOI 7 */
+          BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0x60));
+          service_master_pic();
+          break;
+
+        // IRQ lowest priority commands
+        case 0xC0: // 0 7 6 5 4 3 2 1
+        case 0xC1: // 1 0 7 6 5 4 3 2
+        case 0xC2: // 2 1 0 7 6 5 4 3
+        case 0xC3: // 3 2 1 0 7 6 5 4
+        case 0xC4: // 4 3 2 1 0 7 6 5
+        case 0xC5: // 5 4 3 2 1 0 7 6
+        case 0xC6: // 6 5 4 3 2 1 0 7
+        case 0xC7: // 7 6 5 4 3 2 1 0
+          BX_INFO(("IRQ lowest command 0x%x", value));
+          BX_PIC_THIS s.master_pic.lowest_priority = value - 0xC0;
+          break;
+
+        case 0xE0: // specific EOI and rotate 0
+        case 0xE1: // specific EOI and rotate 1
+        case 0xE2: // specific EOI and rotate 2
+        case 0xE3: // specific EOI and rotate 3
+        case 0xE4: // specific EOI and rotate 4
+        case 0xE5: // specific EOI and rotate 5
+        case 0xE6: // specific EOI and rotate 6
+        case 0xE7: // specific EOI and rotate 7
+          BX_PIC_THIS s.master_pic.isr &= ~(1 << (value-0xE0));
+          BX_PIC_THIS s.master_pic.lowest_priority = (value - 0xE0);
+          service_master_pic();
+
+          break;
+
+        default:
+          BX_PANIC(("write to port 20h = %02x", value));
+       } /* switch (value) */
+      break;
+
+    case 0x21:
+      /* initialization mode operation */
+      if (BX_PIC_THIS s.master_pic.init.in_init) {
+        switch (BX_PIC_THIS s.master_pic.init.byte_expected) {
+          case 2:
+            BX_PIC_THIS s.master_pic.interrupt_offset = value & 0xf8;
+            BX_PIC_THIS s.master_pic.init.byte_expected = 3;
+            BX_DEBUG(("master: init command 2 = %02x", (unsigned) value));
+            BX_DEBUG(("        offset = INT %02x",
+                      BX_PIC_THIS s.master_pic.interrupt_offset));
+            return;
+            break;
+          case 3:
+            BX_DEBUG(("master: init command 3 = %02x", (unsigned) value));
+            if (BX_PIC_THIS s.master_pic.init.requires_4) {
+              BX_PIC_THIS s.master_pic.init.byte_expected = 4;
+             }
+            else {
+              BX_PIC_THIS s.master_pic.init.in_init = 0;
+             }
+            return;
+            break;
+          case 4:
+            BX_DEBUG(("master: init command 4 = %02x", (unsigned) value));
+            if (value & 0x02) {
+              BX_DEBUG(("       auto EOI"));
+              BX_PIC_THIS s.master_pic.auto_eoi = 1;
+              }
+            else {
+              BX_DEBUG(("normal EOI interrupt"));
+              BX_PIC_THIS s.master_pic.auto_eoi = 0;
+              }
+           if (value & 0x01) {
+                 BX_DEBUG(("       80x86 mode"));
+           } else
+                 BX_PANIC(("       not 80x86 mode"));
+            BX_PIC_THIS s.master_pic.init.in_init = 0;
+            return;
+            break;
+          default:
+            BX_PANIC(("master expecting bad init command"));
+          }
+        }
+
+      /* normal operation */
+      BX_DEBUG(("setting master pic IMR to %02x", value));
+      BX_PIC_THIS s.master_pic.imr = value;
+      service_master_pic();
+      return;
+      break;
+
+    case 0xA0:
+      if (value & 0x10) { /* initialization command 1 */
+        BX_DEBUG(("slave: init command 1 found"));
+        BX_DEBUG(("       requires 4 = %u",
+            (unsigned) (value & 0x01) ));
+        BX_DEBUG(("       cascade mode: [0=cascade,1=single] %u",
+            (unsigned) ((value & 0x02) >> 1)));
+        BX_PIC_THIS s.slave_pic.init.in_init = 1;
+        BX_PIC_THIS s.slave_pic.init.requires_4 = (value & 0x01);
+        BX_PIC_THIS s.slave_pic.init.byte_expected = 2; /* operation command 2 */
+        BX_PIC_THIS s.slave_pic.imr           = 0x00; /* clear irq mask */
+        BX_PIC_THIS s.slave_pic.isr           = 0x00; /* no IRQ's in service */
+        BX_PIC_THIS s.slave_pic.irr           = 0x00; /* no IRQ's requested */
+        BX_PIC_THIS s.slave_pic.lowest_priority = 7;
+        BX_PIC_THIS s.slave_pic.INT = 0; /* reprogramming clears previous INTR request */
+        BX_PIC_THIS s.slave_pic.auto_eoi = 0;
+        BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = 0;
+        if (value & 0x02)
+          BX_PANIC(("slave: ICW1: single mode not supported"));
+        if (value & 0x08) {
+          BX_PANIC(("slave: ICW1: level sensitive mode not supported"));
+         }
+       else {
+          BX_DEBUG(("slave: ICW1: edge triggered mode selected"));
+         }
+        return;
+        }
+
+      if ( (value & 0x18) == 0x08 ) { /* OCW3 */
+        Bit8u special_mask, poll, read_op;
+
+        special_mask = (value & 0x60) >> 5;
+        poll         = (value & 0x04) >> 2;
+        read_op      = (value & 0x03);
+        if (poll) {
+          BX_PIC_THIS s.slave_pic.polled = 1;
+          return;
+        }
+        if (read_op == 0x02) /* read IRR */
+         BX_PIC_THIS s.slave_pic.read_reg_select = 0;
+        else if (read_op == 0x03) /* read ISR */
+         BX_PIC_THIS s.slave_pic.read_reg_select = 1;
+        if (special_mask == 0x02) { /* cancel special mask */
+          BX_PIC_THIS s.slave_pic.special_mask = 0;
+          }
+        else if (special_mask == 0x03) { /* set specific mask */
+          BX_PIC_THIS s.slave_pic.special_mask = 1;
+          service_slave_pic();
+          }
+        return;
+        }
+
+      switch (value) {
+        case 0x00: // Rotate in auto eoi mode clear
+        case 0x80: // Rotate in auto eoi mode set
+          BX_PIC_THIS s.slave_pic.rotate_on_autoeoi = (value != 0);
+          break;
+
+       case 0x0A: /* select read interrupt request register */
+         BX_PIC_THIS s.slave_pic.read_reg_select = 0;
+         break;
+       case 0x0B: /* select read interrupt in-service register */
+         BX_PIC_THIS s.slave_pic.read_reg_select = 1;
+         break;
+
+        case 0xA0: // Rotate on non-specific end of interrupt
+        case 0x20: /* end of interrupt command */
+
+          clear_highest_interrupt(& BX_PIC_THIS s.slave_pic);
+
+          if(value == 0xA0) {// Rotate in Auto-EOI mode
+            BX_PIC_THIS s.slave_pic.lowest_priority ++;
+            if(BX_PIC_THIS s.slave_pic.lowest_priority > 7)
+              BX_PIC_THIS s.slave_pic.lowest_priority = 0;
+          }
+
+          service_slave_pic();
+          break;
+
+        case 0x40: // Intel PIC spec-sheet seems to indicate this should be ignored
+          BX_INFO(("IRQ no-op"));
+          break;
+
+        case 0x60: /* specific EOI 0 */
+        case 0x61: /* specific EOI 1 */
+        case 0x62: /* specific EOI 2 */
+        case 0x63: /* specific EOI 3 */
+        case 0x64: /* specific EOI 4 */
+        case 0x65: /* specific EOI 5 */
+        case 0x66: /* specific EOI 6 */
+        case 0x67: /* specific EOI 7 */
+          BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0x60));
+          service_slave_pic();
+          break;
+
+        // IRQ lowest priority commands
+        case 0xC0: // 0 7 6 5 4 3 2 1
+        case 0xC1: // 1 0 7 6 5 4 3 2
+        case 0xC2: // 2 1 0 7 6 5 4 3
+        case 0xC3: // 3 2 1 0 7 6 5 4
+        case 0xC4: // 4 3 2 1 0 7 6 5
+        case 0xC5: // 5 4 3 2 1 0 7 6
+        case 0xC6: // 6 5 4 3 2 1 0 7
+        case 0xC7: // 7 6 5 4 3 2 1 0
+          BX_INFO(("IRQ lowest command 0x%x", value));
+          BX_PIC_THIS s.slave_pic.lowest_priority = value - 0xC0;
+          break;
+
+        case 0xE0: // specific EOI and rotate 0
+        case 0xE1: // specific EOI and rotate 1
+        case 0xE2: // specific EOI and rotate 2
+        case 0xE3: // specific EOI and rotate 3
+        case 0xE4: // specific EOI and rotate 4
+        case 0xE5: // specific EOI and rotate 5
+        case 0xE6: // specific EOI and rotate 6
+        case 0xE7: // specific EOI and rotate 7
+          BX_PIC_THIS s.slave_pic.isr &= ~(1 << (value-0xE0));
+          BX_PIC_THIS s.slave_pic.lowest_priority = (value - 0xE0);
+          service_slave_pic();
+
+          break;
+
+        default:
+          BX_PANIC(("write to port A0h = %02x", value));
+       } /* switch (value) */
+      break;
+
+    case 0xA1:
+      /* initialization mode operation */
+      if (BX_PIC_THIS s.slave_pic.init.in_init) {
+        switch (BX_PIC_THIS s.slave_pic.init.byte_expected) {
+          case 2:
+            BX_PIC_THIS s.slave_pic.interrupt_offset = value & 0xf8;
+            BX_PIC_THIS s.slave_pic.init.byte_expected = 3;
+            BX_DEBUG(("slave: init command 2 = %02x", (unsigned) value));
+            BX_DEBUG(("       offset = INT %02x",
+                      BX_PIC_THIS s.slave_pic.interrupt_offset));
+            return;
+            break;
+          case 3:
+            BX_DEBUG(("slave: init command 3 = %02x", (unsigned) value));
+            if (BX_PIC_THIS s.slave_pic.init.requires_4) {
+              BX_PIC_THIS s.slave_pic.init.byte_expected = 4;
+               } else {
+              BX_PIC_THIS s.slave_pic.init.in_init = 0;
+             }
+            return;
+            break;
+          case 4:
+            BX_DEBUG(("slave: init command 4 = %02x", (unsigned) value));
+            if (value & 0x02) {
+              BX_DEBUG(("       auto EOI"));
+              BX_PIC_THIS s.slave_pic.auto_eoi = 1;
+              }
+            else {
+              BX_DEBUG(("normal EOI interrupt"));
+              BX_PIC_THIS s.slave_pic.auto_eoi = 0;
+              }
+           if (value & 0x01) {
+                 BX_DEBUG(("       80x86 mode"));
+           } else
+                 BX_PANIC(("       not 80x86 mode"));
+            BX_PIC_THIS s.slave_pic.init.in_init = 0;
+            return;
+            break;
+          default:
+            BX_PANIC(("slave: expecting bad init command"));
+          }
+        }
+
+      /* normal operation */
+      BX_DEBUG(("setting slave pic IMR to %02x", value));
+      BX_PIC_THIS s.slave_pic.imr = value;
+      service_slave_pic();
+      return;
+      break;
+    } /* switch (address) */
+
+  return;
+}
+
+// new IRQ signal handling routines
+
+  void
+bx_pic_c::lower_irq(unsigned irq_no)
+{
+#if BX_SUPPORT_APIC
+  // forward this function call to the ioapic too
+  if (DEV_ioapic_present())
+    bx_devices.ioapic->untrigger_irq (irq_no, -1);
+#endif
+
+  if ((irq_no <= 7) && (BX_PIC_THIS s.master_pic.IRQ_line[irq_no])) {
+    BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
+    BX_PIC_THIS s.master_pic.IRQ_line[irq_no] = 0;
+    BX_PIC_THIS s.master_pic.irr &= ~(1 << irq_no);
+    if ((BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr) == 0) {
+      BX_SET_INTR(0);
+      BX_PIC_THIS s.master_pic.INT = 0;
+    }
+  } else if ((irq_no > 7) && (irq_no <= 15) &&
+             (BX_PIC_THIS s.slave_pic.IRQ_line[irq_no-8])) {
+    BX_DEBUG(("IRQ line %d now low", (unsigned) irq_no));
+    BX_PIC_THIS s.slave_pic.IRQ_line[irq_no - 8] = 0;
+    BX_PIC_THIS s.slave_pic.irr &= ~(1 << (irq_no - 8));
+    if ((BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr) == 0) {
+      BX_PIC_THIS s.slave_pic.INT = 0;
+      lower_irq(2);
+    }
+  }
+}
+
+  void
+bx_pic_c::raise_irq(unsigned irq_no)
+{
+#if BX_SUPPORT_APIC
+  // forward this function call to the ioapic too
+  bx_devices.ioapic->trigger_irq (irq_no, -1);
+#endif
+
+  if ((irq_no <= 7) && (!BX_PIC_THIS s.master_pic.IRQ_line[irq_no])) {
+    BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
+    BX_PIC_THIS s.master_pic.IRQ_line[irq_no] = 1;
+    BX_PIC_THIS s.master_pic.irr |= (1 << irq_no);
+    service_master_pic();
+  } else if ((irq_no > 7) && (irq_no <= 15) &&
+             (!BX_PIC_THIS s.slave_pic.IRQ_line[irq_no-8])) {
+    BX_DEBUG(("IRQ line %d now high", (unsigned) irq_no));
+    BX_PIC_THIS s.slave_pic.IRQ_line[irq_no - 8] = 1;
+    BX_PIC_THIS s.slave_pic.irr |= (1 << (irq_no - 8));
+    service_slave_pic();
+  }
+}
+
+void  bx_pic_c::clear_highest_interrupt(bx_pic_t *pic)
+{
+  int irq;
+  int lowest_priority;
+  int highest_priority;
+
+  /* clear highest current in service bit */
+  lowest_priority = pic->lowest_priority;
+  highest_priority = lowest_priority + 1;
+  if(highest_priority > 7)
+    highest_priority = 0;
+
+  irq = highest_priority;
+  do {
+    if (pic->isr & (1 << irq)) {
+      pic->isr &= ~(1 << irq);
+      break; /* Return mask of bit cleared. */
+    }
+
+    irq ++;
+    if(irq > 7)
+      irq = 0;
+  } while(irq != highest_priority);
+
+}
+
+  /* */
+  void
+bx_pic_c::service_master_pic(void)
+{
+  Bit8u unmasked_requests;
+  int irq;
+  Bit8u isr, max_irq;
+  Bit8u highest_priority = BX_PIC_THIS s.master_pic.lowest_priority + 1;
+  if(highest_priority > 7)
+    highest_priority = 0;
+
+  if (BX_PIC_THIS s.master_pic.INT) { /* last interrupt still not acknowleged */
+    return;
+    }
+
+  if (BX_PIC_THIS s.master_pic.special_mask) {
+    /* all priorities may be enabled.  check all IRR bits except ones
+     * which have corresponding ISR bits set
+     */
+    max_irq = highest_priority;
+    }
+  else { /* normal mode */
+    /* Find the highest priority IRQ that is enabled due to current ISR */
+    isr = BX_PIC_THIS s.master_pic.isr;
+    if (isr) {
+      max_irq = highest_priority;
+      while ( (isr & (1 << max_irq)) == 0) {
+        max_irq++;
+        if(max_irq > 7)
+          max_irq = 0;
+        }
+      if (max_irq == highest_priority ) return; /* Highest priority interrupt in-service,
+                                                 * no other priorities allowed */
+      if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
+      }
+    else
+      max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
+    }
+
+
+  /* now, see if there are any higher priority requests */
+  if ((unmasked_requests = (BX_PIC_THIS s.master_pic.irr & ~BX_PIC_THIS s.master_pic.imr)) ) {
+    irq = highest_priority;
+    do {
+      /* for special mode, since we're looking at all IRQ's, skip if
+       * current IRQ is already in-service
+       */
+      if ( ! (BX_PIC_THIS s.master_pic.special_mask && ((BX_PIC_THIS s.master_pic.isr >> irq) & 0x01)) ) {
+        if (unmasked_requests & (1 << irq)) {
+          BX_DEBUG(("signalling IRQ(%u)", (unsigned) irq));
+          BX_PIC_THIS s.master_pic.INT = 1;
+          BX_SET_INTR(1);
+          BX_PIC_THIS s.master_pic.irq = irq;
+          return;
+          } /* if (unmasked_requests & ... */
+        } 
+
+      irq ++;
+      if(irq > 7)
+        irq = 0;
+      } while(irq != max_irq); /* do ... */
+    } /* if (unmasked_requests = ... */
+}
+
+
+  void
+bx_pic_c::service_slave_pic(void)
+{
+  Bit8u unmasked_requests;
+  int irq;
+  Bit8u isr, max_irq;
+  Bit8u highest_priority = BX_PIC_THIS s.slave_pic.lowest_priority + 1;
+  if(highest_priority > 7)
+    highest_priority = 0;
+
+  if (BX_PIC_THIS s.slave_pic.INT) { /* last interrupt still not acknowleged */
+    return;
+    }
+
+  if (BX_PIC_THIS s.slave_pic.special_mask) {
+    /* all priorities may be enabled.  check all IRR bits except ones
+     * which have corresponding ISR bits set
+     */
+    max_irq = highest_priority;
+  }
+  else { /* normal mode */
+    /* Find the highest priority IRQ that is enabled due to current ISR */
+    isr = BX_PIC_THIS s.slave_pic.isr;
+    if (isr) {
+      max_irq = highest_priority;
+      while ( (isr & (1 << max_irq)) == 0) {
+        max_irq++;
+        if(max_irq > 7)
+          max_irq = 0;
+        }
+      if (max_irq == highest_priority ) return; /* Highest priority interrupt in-service,
+                                                 * no other priorities allowed */
+      if (max_irq > 7) BX_PANIC(("error in service_master_pic()"));
+      }
+    else
+      max_irq = highest_priority; /* 0..7 bits in ISR are cleared */
+  }
+
+
+  /* now, see if there are any higher priority requests */
+  if ((unmasked_requests = (BX_PIC_THIS s.slave_pic.irr & ~BX_PIC_THIS s.slave_pic.imr)) ) {
+    irq = highest_priority;
+    do {
+      /* for special mode, since we're looking at all IRQ's, skip if
+       * current IRQ is already in-service
+       */
+      if ( ! (BX_PIC_THIS s.slave_pic.special_mask && ((BX_PIC_THIS s.slave_pic.isr >> irq) & 0x01)) ) {
+        if (unmasked_requests & (1 << irq)) {
+          BX_DEBUG(("slave: signalling IRQ(%u)", (unsigned) 8 + irq));
+
+          BX_PIC_THIS s.slave_pic.INT = 1;
+          BX_PIC_THIS s.slave_pic.irq = irq;
+          BX_PIC_THIS raise_irq(2); /* request IRQ 2 on master pic */
+          return;
+          } /* if (unmasked_requests & ... */
+        }
+
+        irq ++;
+        if(irq > 7)
+          irq = 0;
+      } while(irq != max_irq); /* do ... */
+    } /* if (unmasked_requests = ... */
+}
+
+
+  /* CPU handshakes with PIC after acknowledging interrupt */
+  Bit8u
+bx_pic_c::IAC(void)
+{
+  Bit8u vector;
+  Bit8u irq;
+
+  BX_SET_INTR(0);
+  BX_PIC_THIS s.master_pic.INT = 0;
+  BX_PIC_THIS s.master_pic.irr &= ~(1 << BX_PIC_THIS s.master_pic.irq);
+  // In autoeoi mode don't set the isr bit.
+  if(!BX_PIC_THIS s.master_pic.auto_eoi)
+    BX_PIC_THIS s.master_pic.isr |= (1 << BX_PIC_THIS s.master_pic.irq);
+  else if(BX_PIC_THIS s.master_pic.rotate_on_autoeoi)
+    BX_PIC_THIS s.master_pic.lowest_priority = BX_PIC_THIS s.master_pic.irq;
+
+  if (BX_PIC_THIS s.master_pic.irq != 2) {
+    irq    = BX_PIC_THIS s.master_pic.irq;
+    vector = irq + BX_PIC_THIS s.master_pic.interrupt_offset;
+    }
+  else { /* IRQ2 = slave pic IRQ8..15 */
+    BX_PIC_THIS s.slave_pic.INT = 0;
+    BX_PIC_THIS s.master_pic.IRQ_line[2] = 0;
+    irq    = BX_PIC_THIS s.slave_pic.irq;
+    vector = irq + BX_PIC_THIS s.slave_pic.interrupt_offset;
+    BX_PIC_THIS s.slave_pic.irr &= ~(1 << BX_PIC_THIS s.slave_pic.irq);
+    // In autoeoi mode don't set the isr bit.
+    if(!BX_PIC_THIS s.slave_pic.auto_eoi)
+      BX_PIC_THIS s.slave_pic.isr |= (1 << BX_PIC_THIS s.slave_pic.irq);
+    else if(BX_PIC_THIS s.slave_pic.rotate_on_autoeoi)
+      BX_PIC_THIS s.slave_pic.lowest_priority = BX_PIC_THIS s.slave_pic.irq;
+    service_slave_pic();
+    irq += 8; // for debug printing purposes
+    }
+
+  service_master_pic();
+
+  BX_DBG_IAC_REPORT(vector, irq);
+  return(vector);
+}
+
+  void
+bx_pic_c::show_pic_state(void)
+{
+#if defined(BX_DEBUGGER) && (BX_DEBUGGER == 1)
+dbg_printf("s.master_pic.imr = %02x\n", BX_PIC_THIS s.master_pic.imr);
+dbg_printf("s.master_pic.isr = %02x\n", BX_PIC_THIS s.master_pic.isr);
+dbg_printf("s.master_pic.irr = %02x\n", BX_PIC_THIS s.master_pic.irr);
+dbg_printf("s.master_pic.irq = %02x\n", BX_PIC_THIS s.master_pic.irq);
+dbg_printf("s.slave_pic.imr = %02x\n", BX_PIC_THIS s.slave_pic.imr);
+dbg_printf("s.slave_pic.isr = %02x\n", BX_PIC_THIS s.slave_pic.isr);
+dbg_printf("s.slave_pic.irr = %02x\n", BX_PIC_THIS s.slave_pic.irr);
+dbg_printf("s.slave_pic.irq = %02x\n", BX_PIC_THIS s.slave_pic.irq);
+#endif
+}
diff --git a/tools/ioemu/iodev/pic.h b/tools/ioemu/iodev/pic.h
new file mode 100644 (file)
index 0000000..cfdb126
--- /dev/null
@@ -0,0 +1,97 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pic.h,v 1.11 2003/08/04 16:03:09 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#if BX_USE_PIC_SMF
+#  define BX_PIC_SMF  static
+#  define BX_PIC_THIS thePic->
+#else
+#  define BX_PIC_SMF
+#  define BX_PIC_THIS this->
+#endif
+
+
+
+typedef struct {
+  Bit8u single_PIC;        /* 0=cascaded PIC, 1=master only */
+  Bit8u interrupt_offset;  /* programmable interrupt vector offset */
+  union {
+    Bit8u   slave_connect_mask; /* for master, a bit for each interrupt line
+                                   0=not connect to a slave, 1=connected */
+    Bit8u   slave_id;           /* for slave, id number of slave PIC */
+    } u;
+  Bit8u sfnm;              /* specially fully nested mode: 0=no, 1=yes*/
+  Bit8u buffered_mode;     /* 0=no buffered mode, 1=buffered mode */
+  Bit8u master_slave;      /* master/slave: 0=slave PIC, 1=master PIC */
+  Bit8u auto_eoi;          /* 0=manual EOI, 1=automatic EOI */
+  Bit8u imr;               /* interrupt mask register, 1=masked */
+  Bit8u isr;               /* in service register */
+  Bit8u irr;               /* interrupt request register */
+  Bit8u read_reg_select;   /* 0=IRR, 1=ISR */
+  Bit8u irq;               /* current IRQ number */
+  Bit8u lowest_priority;   /* current lowest priority irq */
+  bx_bool INT;             /* INT request pin of PIC */
+  bx_bool IRQ_line[8];     /* IRQ pins of PIC */
+  struct {
+    bx_bool    in_init;
+    bx_bool    requires_4;
+    int        byte_expected;
+    } init;
+  bx_bool special_mask;
+  bx_bool polled;            /* Set when poll command is issued. */
+  bx_bool rotate_on_autoeoi; /* Set when should rotate in auto-eoi mode. */
+  } bx_pic_t;
+
+
+class bx_pic_c : public bx_pic_stub_c {
+
+public:
+  bx_pic_c(void);
+  ~bx_pic_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+  virtual void   lower_irq(unsigned irq_no);
+  virtual void   raise_irq(unsigned irq_no);
+  virtual Bit8u  IAC(void);
+  virtual void   show_pic_state(void);
+
+private:
+  struct {
+    bx_pic_t master_pic;
+    bx_pic_t slave_pic;
+    } s;
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PIC_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+  BX_PIC_SMF void   service_master_pic(void);
+  BX_PIC_SMF void   service_slave_pic(void);
+  BX_PIC_SMF void   clear_highest_interrupt(bx_pic_t *pic);
+  };
diff --git a/tools/ioemu/iodev/pit.cc b/tools/ioemu/iodev/pit.cc
new file mode 100644 (file)
index 0000000..cf4777a
--- /dev/null
@@ -0,0 +1,856 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit.cc,v 1.15 2003/07/31 12:04:48 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#include "bochs.h"
+
+#if (BX_USE_NEW_PIT==0)
+
+#define LOG_THIS bx_pit.
+
+
+// NOTES ON THE 8253/8254 PIT MODES
+
+// MODE 0: Interrupt on Terminal Count
+// ===================================
+// Writing new count action:
+//   loaded upon next CLK pulse.  counting doesn't start until GATE=1
+// GATE 0..1 transition:
+//   ???
+// GATE 1..0 transition:
+// counter expiration action:
+//   wraps to FFFF
+// * OUT rises until new count val or new control word for mode 0 written
+
+// MODE 1: Programmable Monoflop
+// =============================
+// Writing new count action:
+//   not effective for current process
+// GATE 0..1 transition:
+//   loads counter
+// counter expiration action:
+//   wraps to FFFF
+// NOTES:
+//   OUT rises until new count val or new control word for mode 0 written
+
+// MODE 2: Rate Generator
+// ======================
+// Writing new count action:
+//   ???
+// GATE 0..1 transition:
+//   loads initial count val and starts counting
+// counter expiration action:
+//   reloads after count expires
+// NOTES:
+// * after control word & initial count val N loaded, PIT starts
+//   counting upon next CLK pulse.
+// * when counter reaches 1, OUT drops to a low level, for one
+//   CLK cycle. (short peak pulse generated)
+// * afterwards, the initial count val is automatically reloaded
+//   and the PIT restarts the same counting operation again.
+// * distance of two OUT pulses is N CLK cycles long.
+// * GATE=1 enables, GATE=0 disables counter.
+// * if GATE drops to low level during counting operation and rises
+//     to high level later, PIT loads initial count value at the
+//     rise and starts counting.
+// * PIT starts counting after last data byte written if GATE=1
+// * if the output is low when the gate goes low, the output is
+//   immediately set high.
+
+// MODE 3: Square Wave Generator
+// =============================
+// Writing new count action:
+//   ???
+// GATE 0..1 transition:
+//   ???
+// counter expiration action:
+//   reloads after count expires
+// NOTES:
+// * initially OUT at a high level
+// * drop of GATE to a low level while OUT low, raises OUT to a high level
+// * a rise from a low to a high level at GATE (trigger pulse),
+//   loads the counter with the initial count value and starts
+//   counting operation
+// * a new count value supplied during the course of an active
+//   counting operation doesn't affect the current process.
+//   At the end of the current half cycle, the PIT loads the new value
+// * if the GATE line goes low, count is temporarily halted until GATE
+//   returns high
+// * if the OUT line is high when GATE goes low, OUT is forced low.
+// ??? different for odd/even counts
+
+// MODE 4: Software Triggered Pulse
+// ================================
+// Writing new count action:
+//   ???
+// GATE 0..1 transition:
+//   ???
+// counter expiration action:
+//   wraps to FFFF
+// NOTES:
+
+// MODE 5: Hardware Triggered Pulse
+// ================================
+// Writing new count action:
+//   ???
+// GATE 0..1 transition:
+//   ???
+// counter expiration action:
+//   wraps to FFFF
+// NOTES:
+
+
+
+#define BX_PIT_LATCH_MODE_LSB   10
+#define BX_PIT_LATCH_MODE_MSB   11
+#define BX_PIT_LATCH_MODE_16BIT 12
+
+
+bx_pit_c bx_pit;
+#if BX_USE_PIT_SMF
+#define this (&bx_pit)
+#endif
+
+#ifdef OUT
+#  undef OUT
+#endif
+
+
+bx_pit_c::bx_pit_c( void )
+{
+  put("PIT");
+  settype(PITLOG);
+  memset(&s, 0, sizeof(s));
+
+  /* 8254 PIT (Programmable Interval Timer) */
+
+  BX_PIT_THIS s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
+  BX_PIT_THIS s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
+}
+
+bx_pit_c::~bx_pit_c( void )
+{
+}
+
+
+  int
+bx_pit_c::init( void )
+{
+  DEV_register_irq(0, "8254 PIT");
+  DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1);
+
+  DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1);
+
+  BX_PIT_THIS s.speaker_data_on = 0;
+  BX_PIT_THIS s.refresh_clock_div2 = 0;
+
+  BX_PIT_THIS s.timer[0].mode        = 3;  /* periodic rate generator */
+  BX_PIT_THIS s.timer[0].latch_mode  = BX_PIT_LATCH_MODE_16BIT;
+  BX_PIT_THIS s.timer[0].input_latch_value = 0;
+  BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+  BX_PIT_THIS s.timer[0].output_latch_value = 0;
+  BX_PIT_THIS s.timer[0].output_latch_toggle = 0;
+  BX_PIT_THIS s.timer[0].output_latch_full = 0;
+  BX_PIT_THIS s.timer[0].counter_max = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[0].counter     = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[0].bcd_mode    = 0;  /* binary counting mode */
+  BX_PIT_THIS s.timer[0].GATE        = 1;  /* GATE tied to + logic */
+  BX_PIT_THIS s.timer[0].OUT         = 1;
+  BX_PIT_THIS s.timer[0].active      = 0;
+
+  BX_PIT_THIS s.timer[1].mode        = 3;  /* periodic rate generator */
+  BX_PIT_THIS s.timer[1].latch_mode  = BX_PIT_LATCH_MODE_16BIT;
+  BX_PIT_THIS s.timer[1].input_latch_value = 0;
+  BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+  BX_PIT_THIS s.timer[1].output_latch_value = 0;
+  BX_PIT_THIS s.timer[1].output_latch_toggle = 0;
+  BX_PIT_THIS s.timer[1].output_latch_full = 0;
+  BX_PIT_THIS s.timer[1].counter_max = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[1].counter     = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[1].bcd_mode    = 0;  /* binary counting mode */
+  BX_PIT_THIS s.timer[1].GATE        = 1;  /* GATE tied to + logic */
+  BX_PIT_THIS s.timer[1].OUT         = 1;
+  BX_PIT_THIS s.timer[1].active      = 0;
+
+  BX_PIT_THIS s.timer[2].mode        = 3;  /* periodic rate generator */
+  BX_PIT_THIS s.timer[2].latch_mode  = BX_PIT_LATCH_MODE_16BIT;
+  BX_PIT_THIS s.timer[2].input_latch_value = 0;
+  BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+  BX_PIT_THIS s.timer[2].output_latch_value = 0;
+  BX_PIT_THIS s.timer[2].output_latch_toggle = 0;
+  BX_PIT_THIS s.timer[2].output_latch_full = 0;
+  BX_PIT_THIS s.timer[2].counter_max = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[2].counter     = 0;  /* 0xFFFF + 1 : (1193182 / 65535 = 18.2Hz) */
+  BX_PIT_THIS s.timer[2].bcd_mode    = 0;  /* binary counting mode */
+  BX_PIT_THIS s.timer[2].GATE        = 0;  /* timer2 gate controlled by port 61h bit 0 */
+  BX_PIT_THIS s.timer[2].OUT         = 1;
+  BX_PIT_THIS s.timer[2].active      = 0;
+
+  return(1);
+}
+
+void bx_pit_c::reset(unsigned type) {
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+  bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pit_c::read( Bit32u   address, unsigned int io_len )
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PIT_SMF
+  if (bx_dbg.pit)
+    BX_INFO(("pit: io read from port %04x", (unsigned) address));
+
+  switch (address) {
+    case 0x40: /* timer 0 - system ticks */
+      return( read_counter(0) );
+      break;
+
+    case 0x42: /* timer 2 read */
+      return( read_counter(2) );
+      break;
+
+    case 0x61:
+      /* AT, port 61h */
+      BX_PIT_THIS s.refresh_clock_div2 = !BX_PIT_THIS s.refresh_clock_div2;
+      return( (BX_PIT_THIS s.timer[2].OUT<<5) |
+              (BX_PIT_THIS s.refresh_clock_div2<<4) |
+              (BX_PIT_THIS s.speaker_data_on<<1) |
+              (BX_PIT_THIS s.timer[2].GATE) );
+      break;
+
+    default:
+      BX_PANIC(("pit: unsupported io read from port %04x", address));
+    }
+  return(0); /* keep compiler happy */
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+  bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+  class_ptr->write(address, dvalue, io_len);
+}
+
+  void
+bx_pit_c::write( Bit32u   address, Bit32u   dvalue,
+                unsigned int io_len )
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PIT_SMF
+  Bit8u    command, mode, bcd_mode;
+  Bit8u   value;
+
+  value = (Bit8u  ) dvalue;
+
+  if (bx_dbg.pit)
+    BX_INFO(("pit: write to port %04x = %02x",
+      (unsigned) address, (unsigned) value));
+
+  switch (address) {
+    case 0x40: /* timer 0: write count register */
+      write_count_reg( value, 0 );
+      break;
+
+    case 0x41: /* timer 1: write count register */
+      write_count_reg( value, 1 );
+      break;
+
+    case 0x42: /* timer 2: write count register */
+      write_count_reg( value, 2 );
+      break;
+
+    case 0x43: /* timer 0-2 mode control */
+      /* |7 6 5 4|3 2 1|0|
+       * |-------|-----|-|
+       * |command|mode |bcd/binary|
+       */
+      command  = value >> 4;
+      mode     = (value >> 1) & 0x07;
+      bcd_mode = value & 0x01;
+#if 0
+BX_INFO(("timer 0-2 mode control: comm:%02x mode:%02x bcd_mode:%u",
+  (unsigned) command, (unsigned) mode, (unsigned) bcd_mode));
+#endif
+
+      if ( (mode > 5) || (command > 0x0e) )
+        BX_PANIC(("pit: outp(43h)=%02xh out of range", (unsigned) value));
+      if (bcd_mode)
+        BX_PANIC(("pit: outp(43h)=%02xh: bcd mode unhandled",
+          (unsigned) bcd_mode));
+
+      switch (command) {
+        case 0x0: /* timer 0: counter latch */
+          latch( 0 );
+          break;
+
+        case 0x1: /* timer 0: LSB mode */
+        case 0x2: /* timer 0: MSB mode */
+          BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+            (unsigned) command));
+          break;
+        case 0x3: /* timer 0: 16-bit mode */
+          BX_PIT_THIS s.timer[0].mode = mode;
+          BX_PIT_THIS s.timer[0].latch_mode   = BX_PIT_LATCH_MODE_16BIT;
+          BX_PIT_THIS s.timer[0].input_latch_value = 0;
+          BX_PIT_THIS s.timer[0].input_latch_toggle = 0;
+          BX_PIT_THIS s.timer[0].bcd_mode    = bcd_mode;
+          if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+            BX_PANIC(("pit: outp(43h): comm 3, mode %02x, bcd %02x unhandled",
+              (unsigned) mode, bcd_mode));
+          break;
+        case 0x4: /* timer 1: counter latch */
+          latch( 1 );
+          break;
+
+        case 0x5: /* timer 1: LSB mode */
+        case 0x6: /* timer 1: MSB mode */
+          BX_INFO(("pit: outp(43h): command %02xh unhandled (ignored)",
+            (unsigned) command));
+          break;
+        case 0x7: /* timer 1: 16-bit mode */
+          BX_PIT_THIS s.timer[1].mode = mode;
+          BX_PIT_THIS s.timer[1].latch_mode   = BX_PIT_LATCH_MODE_16BIT;
+          BX_PIT_THIS s.timer[1].input_latch_value = 0;
+          BX_PIT_THIS s.timer[1].input_latch_toggle = 0;
+          BX_PIT_THIS s.timer[1].bcd_mode    = bcd_mode;
+          if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+            BX_PANIC(("pit: outp(43h): comm 7, mode %02x, bcd %02x unhandled",
+              (unsigned) mode, bcd_mode));
+          break;
+        case 0x8: /* timer 2: counter latch */
+          latch( 2 );
+          break;
+
+        case 0x9: /* timer 2: LSB mode */
+        case 0xa: /* timer 2: MSB mode */
+          BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+            (unsigned) command));
+          break;
+        case 0xb: /* timer 2: 16-bit mode */
+          BX_PIT_THIS s.timer[2].mode = mode;
+          BX_PIT_THIS s.timer[2].latch_mode   = BX_PIT_LATCH_MODE_16BIT;
+          BX_PIT_THIS s.timer[2].input_latch_value = 0;
+          BX_PIT_THIS s.timer[2].input_latch_toggle = 0;
+          BX_PIT_THIS s.timer[2].bcd_mode    = bcd_mode;
+          if ( (mode!=3 && mode!=2 && mode!=0) || bcd_mode!=0 )
+            BX_PANIC(("pit: outp(43h): comm Bh, mode %02x, bcd %02x unhandled",
+              (unsigned) mode, bcd_mode));
+          break;
+#if 0
+        case 0xd: /* general counter latch */
+          if (value & 0x08) /* select counter 2 */
+            latch( 2 );
+          if (value & 0x04) /* select counter 1 */
+            latch( 1 );
+          if (value & 0x02) /* select counter 0 */
+            latch( 0 );
+          break;
+
+        case 0xe: /* latch status of timers */
+          BX_PANIC(("pit: outp(43h): command %02xh unhandled",
+            (unsigned) command);
+          break;
+#endif
+        case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+          BX_INFO(("pit: ignoring 8254 command %u", (unsigned) command));
+          break;
+
+        default: /* 0xc & 0xf */
+          BX_PANIC(("pit: outp(43h) command %1xh unhandled",
+            (unsigned) command));
+          break;
+        }
+      break;
+
+    case 0x61:
+      BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
+/*??? only on AT+ */
+      set_GATE(2, value & 0x01);
+#if BX_CPU_LEVEL < 2
+      /* ??? XT: */
+      bx_kbd_port61h_write(value);
+#endif
+      break;
+
+    default:
+      BX_PANIC(("pit: unsupported io write to port %04x = %02x",
+        (unsigned) address, (unsigned) value));
+    }
+}
+
+
+
+
+  void
+bx_pit_c::write_count_reg( Bit8u   value, unsigned timerid )
+{
+  bx_bool xfer_complete;
+
+  switch ( BX_PIT_THIS s.timer[timerid].latch_mode ) {
+    case BX_PIT_LATCH_MODE_16BIT: /* write1=LSB, write2=MSB */
+      if (BX_PIT_THIS s.timer[timerid].input_latch_toggle==0) {
+        BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+        BX_PIT_THIS s.timer[timerid].input_latch_toggle = 1;
+        xfer_complete = 0;
+        if (bx_dbg.pit)
+          BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
+        }
+      else {
+        BX_PIT_THIS s.timer[timerid].input_latch_value |= (value << 8);
+        BX_PIT_THIS s.timer[timerid].input_latch_toggle = 0;
+        xfer_complete = 1;
+        if (bx_dbg.pit)
+          BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
+        }
+      break;
+
+    case BX_PIT_LATCH_MODE_MSB: /* write1=MSB, LSB=0 */
+      BX_PIT_THIS s.timer[timerid].input_latch_value = (value << 8);
+      xfer_complete = 1;
+      if (bx_dbg.pit)
+        BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write H = %02x", (unsigned) value));
+      break;
+
+    case BX_PIT_LATCH_MODE_LSB: /* write1=LSB, MSB=0 */
+      BX_PIT_THIS s.timer[timerid].input_latch_value = value;
+      xfer_complete = 1;
+      if (bx_dbg.pit)
+        BX_INFO(("pit: BX_PIT_THIS s.timer[timerid] write L = %02x", (unsigned) value));
+      break;
+
+    default:
+      BX_PANIC(("write_count_reg: latch_mode unknown"));
+      xfer_complete = 0;
+    }
+
+  if (xfer_complete) {
+    BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].input_latch_value;
+
+    // reprogramming counter clears latch
+    BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+
+    // counter bounds
+    // mode      minimum    maximum
+    //  0           1          0
+    //  1           1          0
+    //  2           2          0
+    //  3           2          0
+    //  4           1          0
+    //  5           1          0
+    switch (BX_PIT_THIS s.timer[timerid].mode) {
+      case 0:
+        BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+        BX_PIT_THIS s.timer[timerid].active = 1;
+        if (BX_PIT_THIS s.timer[timerid].GATE) {
+          BX_PIT_THIS s.timer[timerid].OUT = 0; // OUT pin starts low
+          start( timerid );
+          }
+        break;
+      case 1:
+        BX_PANIC(("pit:write_count_reg(%u): mode1 unsupported",
+                 timerid));
+        break;
+      case 2:
+        if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+          BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
+                   timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+        if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+          // software triggered
+          BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+          BX_PIT_THIS s.timer[timerid].active  = 1;
+          BX_PIT_THIS s.timer[timerid].OUT     = 1; // initially set high
+          start( timerid );
+          }
+        break;
+      case 3:
+        if ( BX_PIT_THIS s.timer[timerid].counter_max == 1 )
+          BX_PANIC(("pit:write_count_reg(%u): mode %u counter_max=1",
+                   timerid, (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+        BX_PIT_THIS s.timer[timerid].counter_max = BX_PIT_THIS s.timer[timerid].counter_max & 0xfffe;
+        if ( BX_PIT_THIS s.timer[timerid].GATE && !BX_PIT_THIS s.timer[timerid].active ) {
+          // software triggered
+          BX_PIT_THIS s.timer[timerid].counter = BX_PIT_THIS s.timer[timerid].counter_max;
+          BX_PIT_THIS s.timer[timerid].active  = 1;
+          BX_PIT_THIS s.timer[timerid].OUT     = 1; // initially set high
+          start( timerid );
+          }
+        break;
+      case 4:
+        BX_PANIC(("pit:write_count_reg(%u): mode4 unsupported",
+                 timerid));
+        break;
+      case 5:
+        BX_PANIC(("pit:write_count_reg(%u): mode5 unsupported",
+                 timerid));
+        break;
+      }
+    }
+}
+
+
+  Bit8u
+bx_pit_c::read_counter( unsigned timerid )
+{
+  Bit16u  counter_value;
+  Bit8u    retval;
+
+  if (BX_PIT_THIS s.timer[timerid].output_latch_full) { /* latched read */
+    counter_value = BX_PIT_THIS s.timer[timerid].output_latch_value;
+    }
+  else { /* direct unlatched read */
+    counter_value = BX_PIT_THIS s.timer[timerid].counter;
+BX_INFO(("CV=%04x", (unsigned) BX_PIT_THIS s.timer[timerid].counter));
+    }
+
+  switch (BX_PIT_THIS s.timer[timerid].latch_mode) {
+    case BX_PIT_LATCH_MODE_LSB:
+      retval = (Bit8u  ) counter_value;
+      BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+      break;
+    case BX_PIT_LATCH_MODE_MSB:
+      retval = (Bit8u  ) ( counter_value >> 8 );
+      BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+      break;
+    case BX_PIT_LATCH_MODE_16BIT:
+      if (BX_PIT_THIS s.timer[timerid].output_latch_toggle==0) { /* LSB 1st */
+        retval = (Bit8u  ) counter_value;
+        }
+      else { /* MSB 2nd */
+        retval = (Bit8u  ) ( counter_value >> 8 );
+        }
+      BX_PIT_THIS s.timer[timerid].output_latch_toggle = !BX_PIT_THIS s.timer[timerid].output_latch_toggle;
+      if (BX_PIT_THIS s.timer[timerid].output_latch_toggle == 0)
+        BX_PIT_THIS s.timer[timerid].output_latch_full = 0;
+      break;
+    default:
+      BX_PANIC(("pit: io read from port 40h: unknown latch mode"));
+      retval = 0; /* keep compiler happy */
+    }
+  return( retval );
+}
+
+
+  void
+bx_pit_c::latch( unsigned timerid )
+{
+  /* subsequent counter latch commands are ignored until value read out */
+  if (BX_PIT_THIS s.timer[timerid].output_latch_full) {
+    BX_INFO(("pit: pit(%u) latch: output latch full, ignoring",
+              timerid));
+    return;
+    }
+
+  BX_PIT_THIS s.timer[timerid].output_latch_value = BX_PIT_THIS s.timer[timerid].counter;
+
+  if (bx_dbg.pit)
+    BX_INFO(("pit: latch_value = %u", (unsigned) BX_PIT_THIS s.timer[timerid].output_latch_value));
+  BX_PIT_THIS s.timer[timerid].output_latch_toggle = 0;
+  BX_PIT_THIS s.timer[timerid].output_latch_full   = 1;
+}
+
+  void
+bx_pit_c::set_GATE(unsigned pit_id, unsigned value)
+{
+  // GATE's for Timer 0 & Timer 1 are tied high.
+  if (pit_id != 2)
+    BX_PANIC(("pit:set_GATE: pit_id != 2"));
+
+  value = (value > 0);
+
+  /* if no transition of GATE input line, then nothing to do */
+  if (value == BX_PIT_THIS s.timer[2].GATE)
+    return;
+
+  if (value) { /* PIT2: GATE transition from 0 to 1 */
+    BX_PIT_THIS s.timer[2].GATE  = 1;
+    switch ( BX_PIT_THIS s.timer[2].mode ) {
+      case 0:
+        BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+        if (BX_PIT_THIS s.timer[2].active) {
+          BX_PIT_THIS s.timer[2].OUT = 0;
+          }
+        start( 2 );
+        break;
+      case 2:
+        // begin counting, reload counter
+        BX_PIT_THIS s.timer[2].active = 1;
+        BX_PIT_THIS s.timer[2].OUT = 1;
+        BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+        start( 2 );
+        break;
+      case 3:
+        // begin counting, reload counter
+        BX_PIT_THIS s.timer[2].active = 1;
+        BX_PIT_THIS s.timer[2].OUT = 1;
+        BX_PIT_THIS s.timer[2].counter = BX_PIT_THIS s.timer[2].counter_max;
+        start( 2 );
+        break;
+      case 1:
+      case 4:
+      case 5:
+      default:
+        BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
+                 (unsigned) BX_PIT_THIS s.timer[2].mode));
+      }
+    }
+  else {       // PIT2: GATE transition from 1 to 0, deactivate
+    BX_PIT_THIS s.timer[2].GATE  = 0;
+    switch ( BX_PIT_THIS s.timer[2].mode ) {
+      case 0:
+        break;
+      case 2:
+        // 1) stops count, 2) OUT goes immediately high
+        BX_PIT_THIS s.timer[2].active = 0;
+        BX_PIT_THIS s.timer[2].OUT = 1;
+        break;
+      case 3:
+        // 1) stops count, 2) OUT goes immediately high
+        BX_PIT_THIS s.timer[2].active = 0;
+        BX_PIT_THIS s.timer[2].OUT = 1;
+        break;
+      case 1:
+      case 4:
+      case 5:
+      default:
+        BX_PANIC(("bx_pit_c::set_GATE: unhandled timer2 mode %u",
+                 (unsigned) BX_PIT_THIS s.timer[2].mode));
+      }
+    }
+}
+
+
+  void
+bx_pit_c::start(unsigned timerid)
+{
+  unsigned long period_hz;
+
+  if (BX_PIT_THIS s.timer[timerid].counter_max == 0x0000) {
+    period_hz   = 1193182 / 65536;
+    }
+  else {
+    period_hz = 1193182 / BX_PIT_THIS s.timer[timerid].counter_max;
+    }
+  BX_INFO(("timer%u period set to %lu hz", timerid, period_hz));
+
+
+  switch (BX_PIT_THIS s.timer[timerid].mode) {
+    case 0: /* single timeout */
+      break;
+    case 1: /* retriggerable one-shot */
+      BX_PANIC(("start: mode %u unhandled",
+               (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+      break;
+    case 2: /* rate generator */
+      break;
+    case 3: /* square wave mode */
+      break;
+    case 4: /* software triggered strobe */
+      BX_PANIC(("start: mode %u unhandled",
+               (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+      break;
+    case 5: /* hardware retriggerable strobe */
+      BX_PANIC(("start: mode %u unhandled",
+               (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+      break;
+    default:
+      BX_PANIC(("start: timer%u has bad mode",
+               (unsigned) BX_PIT_THIS s.timer[timerid].mode));
+    }
+}
+
+
+
+
+  int
+bx_pit_c::SaveState( class state_file *fd )
+{
+  fd->write_check ("8254 start");
+  fd->write (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+  fd->write_check ("8254 end");
+  return(0);
+}
+
+
+  int
+bx_pit_c::LoadState( class state_file *fd )
+{
+  fd->read_check ("8254 start");
+  fd->read (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+  fd->read_check ("8254 end");
+  return(0);
+}
+
+
+#if 0
+  void
+bx_kbd_port61h_write(Bit8u   value)
+{
+//  PcError("KBD_PORT61H_WRITE(): not implemented yet");
+  UNUSED( value );
+}
+#endif
+
+
+  bx_bool
+bx_pit_c::periodic( Bit32u   usec_delta )
+{
+  bx_bool prev_timer0_out;
+
+  prev_timer0_out = BX_PIT_THIS s.timer[0].OUT;
+
+  for (unsigned i = 0; i < 3; i++) {
+    // is timer enabled and active?
+    if ( BX_PIT_THIS s.timer[i].GATE && BX_PIT_THIS s.timer[i].active ) {
+      switch ( BX_PIT_THIS s.timer[i].mode ) {
+        case 0: // Mode 0: Single Timeout
+          // wraps after count expires
+          if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+            // counter previously expired, wrap counter
+            BX_PIT_THIS s.timer[i].counter = 0xffff;
+            }
+          else if ( usec_delta >= BX_PIT_THIS s.timer[i].counter ) {
+            // counter expired
+            BX_PIT_THIS s.timer[i].counter = 0;
+            BX_PIT_THIS s.timer[i].OUT     = 1;
+            }
+          else {
+            // decrement counter by elapsed useconds
+            BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+            }
+          break;
+
+        case 1: // Mode 1: Retriggerable One-Shot
+          // wraps after count expires
+          BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+                        i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+          break;
+
+        case 2: // Mode 2: Rate Generator
+          // reloads after count expires
+          // OUT is low when counter=1, high otherwise
+          // min count=2, max count=0
+          if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+            // max counter val, just wrap
+            BX_PIT_THIS s.timer[i].counter = 0xffff;
+            BX_PIT_THIS s.timer[i].OUT     = 1;
+            }
+          else if ( BX_PIT_THIS s.timer[i].counter == 1 ) {
+            // counter previously expired, reload
+            BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+            BX_PIT_THIS s.timer[i].OUT     = 1;
+            }
+          else if ( (BX_PIT_THIS s.timer[i].counter == 2) ||
+                    (usec_delta >= (Bit32u(BX_PIT_THIS s.timer[i].counter) - 1)) ) {
+            // in either case, counter will reach 1
+            BX_PIT_THIS s.timer[i].counter = 1;
+            BX_PIT_THIS s.timer[i].OUT = 0;
+            }
+          else {
+            // decrement counter by elapsed useconds
+            BX_PIT_THIS s.timer[i].counter -= (Bit16u ) usec_delta;
+            }
+          break;
+
+        case 3: // Mode 3: Square Wave Mode
+          // reloads after count expires
+          // min count=2, max count=0
+          if ( BX_PIT_THIS s.timer[i].counter == 0 ) {
+            // max count, dec by 2
+            BX_PIT_THIS s.timer[i].counter = 0xfffe;
+            }
+          else if ( (BX_PIT_THIS s.timer[i].counter <= 2) ||
+                    ( (usec_delta*2) >= BX_PIT_THIS s.timer[i].counter ) ) {
+            // counter expired, reload
+            BX_PIT_THIS s.timer[i].counter = BX_PIT_THIS s.timer[i].counter_max;
+            BX_PIT_THIS s.timer[i].OUT     = !BX_PIT_THIS s.timer[i].OUT;
+            //BX_INFO(("CV: reload t%u to %04x", (unsigned) i, (unsigned)
+            //  BX_PIT_THIS s.timer[i].counter));
+            }
+          else {
+            // decrement counter by elapsed useconds
+            BX_PIT_THIS s.timer[i].counter -= (Bit16u ) ( 2*usec_delta );
+            //BX_INFO(("CV: dec count to %04x",
+            //          (unsigned) BX_PIT_THIS s.timer[i].counter));
+            }
+          break;
+
+        case 4: // Mode 4: Software Triggered Strobe
+          // wraps after count expires
+          BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+                        i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+          break;
+
+        case 5: // Mode 5: Hardware Retriggerable Strobe
+          // wraps after count expires
+          BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+                        i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+          break;
+        default:
+          BX_PANIC(("bx_pit_c::periodic: bad mode: timer[%u], mode %u",
+                        i, (unsigned) BX_PIT_THIS s.timer[i].mode));
+          break;
+        } // switch ( BX_PIT_THIS s.tim...
+      } // if ( BX_PIT_THIS s.timer[i]...
+    } // for (unsigned i...
+
+  // see if there's a rising edge on timer0's output to trigger an IRQ0.
+  if ( (prev_timer0_out==0) && (BX_PIT_THIS s.timer[0].OUT==1) )
+    return(1); // request IRQ 0
+  else
+    return(0);
+}
+
+#endif // #if (BX_USE_NEW_PIT==0)
diff --git a/tools/ioemu/iodev/pit.h b/tools/ioemu/iodev/pit.h
new file mode 100644 (file)
index 0000000..49b663b
--- /dev/null
@@ -0,0 +1,103 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit.h,v 1.10 2002/10/25 11:44:40 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#ifndef _BX_PIT_H
+#define _BX_PIT_H
+
+#include "config.h"
+
+#if (BX_USE_NEW_PIT==0)
+
+#if BX_USE_PIT_SMF
+#  define BX_PIT_SMF  static
+#  define BX_PIT_THIS bx_pit.
+#else
+#  define BX_PIT_SMF
+#  define BX_PIT_THIS this->
+#endif
+
+#ifdef OUT
+#  undef OUT
+#endif
+
+
+typedef struct {
+  Bit8u      mode;
+  Bit8u      latch_mode;
+  Bit16u     input_latch_value;
+  bx_bool    input_latch_toggle;
+  Bit16u     output_latch_value;
+  bx_bool    output_latch_toggle;
+  bx_bool    output_latch_full;
+  Bit16u     counter_max;
+  Bit16u     counter;
+  bx_bool    bcd_mode;
+  bx_bool    active;
+  bx_bool    GATE;     // GATE input  pin
+  bx_bool    OUT;      // OUT  output pin
+  } bx_pit_t;
+
+
+
+
+class bx_pit_c : public logfunctions {
+public:
+  bx_pit_c( void );
+  ~bx_pit_c( void );
+  BX_PIT_SMF int init(void);
+  BX_PIT_SMF void reset( unsigned type);
+  BX_PIT_SMF bx_bool periodic( Bit32u   usec_delta );
+
+  BX_PIT_SMF int SaveState( class state_file *fd );
+  BX_PIT_SMF int LoadState( class state_file *fd );
+
+private:
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PIT_SMF
+  Bit32u   read( Bit32u   addr, unsigned int len );
+  void write( Bit32u   addr, Bit32u   Value, unsigned int len );
+#endif
+
+  struct s_type {
+    bx_pit_t timer[3];
+    Bit8u   speaker_data_on;
+    bx_bool refresh_clock_div2;
+    int  timer_handle[3];
+    } s;
+
+  BX_PIT_SMF void  write_count_reg( Bit8u   value, unsigned timerid );
+  BX_PIT_SMF Bit8u read_counter( unsigned timerid );
+  BX_PIT_SMF void  latch( unsigned timerid );
+  BX_PIT_SMF void  set_GATE(unsigned pit_id, unsigned value);
+  BX_PIT_SMF void  start(unsigned timerid);
+  };
+
+extern bx_pit_c bx_pit;
+
+#endif  // #if (BX_USE_NEW_PIT==0)
+#endif  // #ifndef _BX_PIT_H
diff --git a/tools/ioemu/iodev/pit82c54.cc b/tools/ioemu/iodev/pit82c54.cc
new file mode 100644 (file)
index 0000000..fc913b1
--- /dev/null
@@ -0,0 +1,893 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit82c54.cc,v 1.23 2003/06/29 17:24:52 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ * Emulator of an Intel 8254/82C54 Programmable Interval Timer.
+ * Greg Alexander <yakovlev@usa.com>
+ *
+ * 
+ * Things I am unclear on (greg):
+ * 1.)What happens if both the status and count registers are latched,
+ *  but the first of the two count registers has already been read?
+ *  I.E.: 
+ *   latch count 0 (16-bit)
+ *   Read count 0 (read LSByte)
+ *   READ_BACK status of count 0
+ *   Read count 0 - do you get MSByte or status?
+ *  This will be flagged as an error.
+ * 2.)What happens when we latch the output in the middle of a 2-part
+ *  unlatched read?
+ * 3.)I assumed that programming a counter removes a latched status.
+ * 4.)I implemented the 8254 description of mode 0, not the 82C54 one.
+ * 5.)clock() calls represent a rising clock edge followed by a falling
+ *  clock edge.
+ * 6.)What happens when we trigger mode 1 in the middle of a 2-part 
+ *  write?
+ */
+
+#include "bochs.h"
+#include "pit82c54.h"
+#define LOG_THIS this->
+
+
+void pit_82C54::print_counter(counter_type & thisctr) {
+#if 1
+  BX_INFO(("Printing Counter"));
+  BX_INFO(("count: %d",thisctr.count));
+  BX_INFO(("count_binary: %x",thisctr.count_binary));
+  BX_INFO(("counter gate: %x",thisctr.GATE));
+  BX_INFO(("counter OUT: %x",thisctr.OUTpin));
+  BX_INFO(("next_change_time: %d",thisctr.next_change_time));
+  BX_INFO(("End Counter Printout"));
+#endif
+}
+
+void pit_82C54::print_cnum(Bit8u cnum) {
+  if(cnum>MAX_COUNTER) {
+    BX_ERROR(("Bad counter index to print_cnum"));
+  } else {
+    print_counter(counter[cnum]);
+  }
+}
+
+  void pit_82C54::latch_counter(counter_type & thisctr) {
+    if(thisctr.count_LSB_latched || thisctr.count_MSB_latched) {
+      //Do nothing because previous latch has not been read.;
+    } else {
+      switch(thisctr.read_state) {
+      case MSByte:
+       thisctr.outlatch=thisctr.count & 0xFFFF;
+       thisctr.count_MSB_latched=1;
+       break;
+      case LSByte:
+       thisctr.outlatch=thisctr.count & 0xFFFF;
+       thisctr.count_LSB_latched=1;
+       break;
+      case LSByte_multiple:
+       thisctr.outlatch=thisctr.count & 0xFFFF;
+       thisctr.count_LSB_latched=1;
+       thisctr.count_MSB_latched=1;
+       break;
+      case MSByte_multiple:
+       if(!(seen_problems & UNL_2P_READ)) {
+//       seen_problems|=UNL_2P_READ;
+         BX_ERROR(("Unknown behavior when latching during 2-part read."));
+         BX_ERROR(("  This message will not be repeated."));
+       }
+       //I guess latching and resetting to LSB first makes sense;
+       BX_DEBUG(("Setting read_state to LSB_mult"));
+       thisctr.read_state=LSByte_multiple;
+       thisctr.outlatch=thisctr.count & 0xFFFF;
+       thisctr.count_LSB_latched=1;
+       thisctr.count_MSB_latched=1;
+       break;
+      default:
+       BX_ERROR(("Unknown read mode found during latch command."));
+       break;
+      }
+    }
+  }
+
+  void pit_82C54::set_OUT (counter_type & thisctr, bool data) {
+    //This will probably have a callback, so I put it here.
+    thisctr.OUTpin=data;
+  }
+
+  void  BX_CPP_AttrRegparmN(2)
+pit_82C54::set_count (counter_type & thisctr, Bit32u data) {
+    thisctr.count=data & 0xFFFF;
+    set_binary_to_count(thisctr);
+  }
+
+  void  BX_CPP_AttrRegparmN(1)
+pit_82C54::set_count_to_binary(counter_type & thisctr) {
+    if(thisctr.bcd_mode) {
+      thisctr.count=
+       (((thisctr.count_binary/1)%10)<<0) |
+       (((thisctr.count_binary/10)%10)<<4) |
+       (((thisctr.count_binary/100)%10)<<8) |
+       (((thisctr.count_binary/1000)%10)<<12)
+       ;
+    } else {
+      thisctr.count=thisctr.count_binary;
+    }
+  }
+
+  void  BX_CPP_AttrRegparmN(1)
+pit_82C54::set_binary_to_count(counter_type & thisctr) {
+    if(thisctr.bcd_mode) {
+      thisctr.count_binary=
+       (1*((thisctr.count>>0)&0xF)) +
+       (10*((thisctr.count>>4)&0xF)) +
+       (100*((thisctr.count>>8)&0xF)) +
+       (1000*((thisctr.count>>12)&0xF))
+       ;
+    } else {
+      thisctr.count_binary=thisctr.count;
+    }
+  }
+
+  void  BX_CPP_AttrRegparmN(1)
+pit_82C54::decrement (counter_type & thisctr) {
+    if(!thisctr.count) {
+      if(thisctr.bcd_mode) {
+       thisctr.count=0x9999;
+       thisctr.count_binary=9999;
+      } else {
+       thisctr.count=0xFFFF;
+       thisctr.count_binary=0xFFFF;
+      }
+    } else {
+      thisctr.count_binary--;
+      set_count_to_binary(thisctr);
+    }
+  }
+
+  void pit_82C54::init (void) {
+    Bit8u i;
+
+    put("PIT81");
+    settype(PIT81LOG);
+
+    for(i=0;i<3;i++) {
+      BX_DEBUG(("Setting read_state to LSB"));
+      counter[i].read_state=LSByte;
+      counter[i].write_state=LSByte;
+      counter[i].GATE=1;
+      counter[i].OUTpin=1;
+      counter[i].triggerGATE=0;
+      counter[i].mode=4;
+      counter[i].first_pass=0;
+      counter[i].bcd_mode=0;
+      counter[i].count=0;
+      counter[i].count_binary=0;
+      counter[i].state_bit_1=0;
+      counter[i].state_bit_2=0;
+      counter[i].null_count=0;
+      counter[i].rw_mode=1;
+      counter[i].count_written=1;
+      counter[i].count_LSB_latched=0;
+      counter[i].count_MSB_latched=0;
+      counter[i].status_latched=0;
+      counter[i].next_change_time=0;
+    }
+    seen_problems=0;
+  }
+
+  pit_82C54::pit_82C54 (void) {
+    init();
+  }
+
+  void pit_82C54::reset (unsigned type) {
+  }
+
+void  BX_CPP_AttrRegparmN(2)
+pit_82C54::decrement_multiple(counter_type & thisctr, Bit32u cycles) {
+  while(cycles>0) {
+    if(cycles<=thisctr.count_binary) {
+      thisctr.count_binary-=cycles;
+      cycles-=cycles;
+      set_count_to_binary(thisctr);
+    } else {
+      cycles-=(thisctr.count_binary+1);
+      thisctr.count_binary-=thisctr.count_binary;
+      set_count_to_binary(thisctr);
+      decrement(thisctr);
+    }
+  }
+}
+
+void pit_82C54::clock_multiple(Bit8u cnum, Bit32u cycles) {
+  if(cnum>MAX_COUNTER) {
+    BX_ERROR(("Counter number too high in clock"));
+  } else {
+    counter_type & thisctr = counter[cnum];
+    while(cycles>0) {
+      if(thisctr.next_change_time==0) {
+       if(thisctr.count_written) {
+         switch(thisctr.mode) {
+         case 0:
+           if(thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
+             decrement_multiple(thisctr, cycles);
+           }
+           break;
+         case 1:
+           decrement_multiple(thisctr, cycles);
+           break;
+         case 2:
+           if( (!thisctr.first_pass) && thisctr.GATE ) {
+             decrement_multiple(thisctr, cycles);
+           }
+           break;
+         case 3:
+           if( (!thisctr.first_pass) && thisctr.GATE ) {
+             decrement_multiple(thisctr, 2*cycles);
+           }
+           break;
+         case 4:
+           if(thisctr.GATE) {
+             decrement_multiple(thisctr, cycles);
+           }
+           break;
+         case 5:
+           decrement_multiple(thisctr, cycles);
+           break;
+         default:
+           break;
+         }
+       }
+       cycles-=cycles;
+      } else {
+       switch(thisctr.mode) {
+       case 0:
+       case 1:
+       case 2:
+       case 4:
+       case 5:
+         if( thisctr.next_change_time > cycles ) {
+           decrement_multiple(thisctr,cycles);
+           thisctr.next_change_time-=cycles;
+           cycles-=cycles;
+         } else {
+           decrement_multiple(thisctr,(thisctr.next_change_time-1));
+           cycles-=thisctr.next_change_time;
+           clock(cnum);
+         }
+         break;
+       case 3:
+         if( thisctr.next_change_time > cycles ) {
+           decrement_multiple(thisctr,cycles*2);
+           thisctr.next_change_time-=cycles;
+           cycles-=cycles;
+         } else {
+           decrement_multiple(thisctr,(thisctr.next_change_time-1)*2);
+           cycles-=thisctr.next_change_time;
+           clock(cnum);
+         }
+         break;
+       default:
+         cycles-=cycles;
+         break;
+       }
+      }
+    }
+#if 0
+    print_counter(thisctr);
+#endif
+  }
+}
+
+  void  BX_CPP_AttrRegparmN(1)
+pit_82C54::clock(Bit8u cnum) {
+    if(cnum>MAX_COUNTER) {
+      BX_ERROR(("Counter number too high in clock"));
+    } else {
+      counter_type & thisctr = counter[cnum];
+      switch(thisctr.mode) {
+      case 0:
+       if(thisctr.count_written) {
+         if(thisctr.null_count) {
+           set_count(thisctr, thisctr.inlatch);
+           if(thisctr.GATE) {
+              if(thisctr.count_binary==0) {
+               thisctr.next_change_time=1;
+              } else {
+               thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+           thisctr.null_count=0;
+         } else {
+           if(thisctr.GATE && (thisctr.write_state!=MSByte_multiple)) {
+             decrement(thisctr);
+             if(!thisctr.OUTpin) {
+               thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+               if(!thisctr.count) {
+                 set_OUT(thisctr,1);
+               }
+             } else {
+               thisctr.next_change_time=0;
+             }
+           } else {
+             thisctr.next_change_time=0; //if the clock isn't moving.
+           }
+         }
+       } else {
+         thisctr.next_change_time=0; //default to 0.
+       }
+       thisctr.triggerGATE=0;
+       break;
+      case 1:
+       if(thisctr.count_written) {
+         if(thisctr.triggerGATE) {
+           set_count(thisctr, thisctr.inlatch);
+            if(thisctr.count_binary==0) {
+              thisctr.next_change_time=1;
+            } else {
+              thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+            }
+           thisctr.null_count=0;
+           set_OUT(thisctr,0);
+           if(thisctr.write_state==MSByte_multiple) {
+             BX_ERROR(("Undefined behavior when loading a half loaded count."));
+           }
+         } else {
+           decrement(thisctr);
+           if(!thisctr.OUTpin) {
+              if(thisctr.count_binary==0) {
+               thisctr.next_change_time=1;
+              } else {
+               thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+             }
+             if(thisctr.count==0) {
+               set_OUT(thisctr,1);
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+       } else {
+         thisctr.next_change_time=0; //default to 0.
+       }
+       thisctr.triggerGATE=0;
+       break;
+      case 2:
+       if(thisctr.count_written) {
+         if(thisctr.triggerGATE || thisctr.first_pass) {
+           set_count(thisctr, thisctr.inlatch);
+           thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
+           thisctr.null_count=0;
+           if(thisctr.inlatch==1) {
+             BX_ERROR(("ERROR: count of 1 is invalid in pit mode 2."));
+           }
+           if(!thisctr.OUTpin) {
+             set_OUT(thisctr,1);
+           }
+           if(thisctr.write_state==MSByte_multiple) {
+             BX_ERROR(("Undefined behavior when loading a half loaded count."));
+           }
+           thisctr.first_pass=0;
+         } else {
+           if(thisctr.GATE) {
+             decrement(thisctr);
+             thisctr.next_change_time=(thisctr.count_binary-1) & 0xFFFF;
+             if(thisctr.count==1) {
+               thisctr.next_change_time=1;
+               set_OUT(thisctr,0);
+               thisctr.first_pass=1;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+       } else {
+         thisctr.next_change_time=0;
+       }
+       thisctr.triggerGATE=0;
+       break;
+      case 3:
+       if(thisctr.count_written) {
+         if( (thisctr.triggerGATE || thisctr.first_pass
+            || thisctr.state_bit_2) && thisctr.GATE ) {
+           set_count(thisctr, thisctr.inlatch & 0xFFFE);
+           thisctr.state_bit_1=thisctr.inlatch & 0x1;
+           if( (!thisctr.OUTpin) || (!(thisctr.state_bit_1))) {
+              if(((thisctr.count_binary/2)-1)==0) {
+                thisctr.next_change_time=1;
+              } else {
+               thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
+              }
+           } else {
+              if((thisctr.count_binary/2)==0) {
+                thisctr.next_change_time=1;
+              } else {
+               thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
+              }
+           }
+           thisctr.null_count=0;
+           if(thisctr.inlatch==1) {
+             BX_ERROR(("Count of 1 is invalid in pit mode 3."));
+           }
+           if(!thisctr.OUTpin) {
+             set_OUT(thisctr,1);
+           } else if(thisctr.OUTpin && !thisctr.first_pass) {
+             set_OUT(thisctr,0);
+           }
+           if(thisctr.write_state==MSByte_multiple) {
+             BX_ERROR(("Undefined behavior when loading a half loaded count."));
+           }
+           thisctr.state_bit_2=0;
+           thisctr.first_pass=0;
+         } else {
+           if(thisctr.GATE) {
+             decrement(thisctr);
+             decrement(thisctr);
+             if( (!thisctr.OUTpin) || (!(thisctr.state_bit_1))) {
+               thisctr.next_change_time=((thisctr.count_binary/2)-1) & 0xFFFF;
+             } else {
+               thisctr.next_change_time=(thisctr.count_binary/2) & 0xFFFF;
+             }
+             if(thisctr.count==0) {
+               thisctr.state_bit_2=1;
+               thisctr.next_change_time=1;
+             }
+             if( (thisctr.count==2) &&
+                ( (!thisctr.OUTpin) || (!(thisctr.state_bit_1)))
+                ) {
+               thisctr.state_bit_2=1;
+               thisctr.next_change_time=1;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+       } else {
+         thisctr.next_change_time=0;
+       }
+       thisctr.triggerGATE=0;
+       break;
+      case 4:
+       if(thisctr.count_written) {
+         if(!thisctr.OUTpin) {
+           set_OUT(thisctr,1);
+         }
+         if(thisctr.null_count) {
+           set_count(thisctr, thisctr.inlatch);
+           if(thisctr.GATE) {
+              if(thisctr.count_binary==0) {
+               thisctr.next_change_time=1;
+             } else {
+               thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+           thisctr.null_count=0;
+           if(thisctr.write_state==MSByte_multiple) {
+             BX_ERROR(("Undefined behavior when loading a half loaded count."));
+           }
+           thisctr.first_pass=1;
+         } else {
+           if(thisctr.GATE) {
+             decrement(thisctr);
+             if(thisctr.first_pass) {
+               thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+               if(!thisctr.count) {
+                 set_OUT(thisctr,0);
+                 thisctr.next_change_time=1;
+                 thisctr.first_pass=0;
+               }
+             } else {
+               thisctr.next_change_time=0;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+       } else {
+         thisctr.next_change_time=0;
+       }
+       thisctr.triggerGATE=0;
+       break;
+      case 5:
+       if(thisctr.count_written) {
+         if(!thisctr.OUTpin) {
+           set_OUT(thisctr,1);
+         }
+         if(thisctr.triggerGATE) {
+           set_count(thisctr, thisctr.inlatch);
+            if(thisctr.count_binary==0) {
+             thisctr.next_change_time=1;
+           } else {
+              thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+            }
+           thisctr.null_count=0;
+           if(thisctr.write_state==MSByte_multiple) {
+             BX_ERROR(("Undefined behavior when loading a half loaded count."));
+           }
+           thisctr.first_pass=1;
+         } else {
+           decrement(thisctr);
+           if(thisctr.first_pass) {
+             thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+             if(!thisctr.count) {
+               set_OUT(thisctr,0);
+               thisctr.next_change_time=1;
+               thisctr.first_pass=0;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+       } else {
+         thisctr.next_change_time=0;
+       }
+       thisctr.triggerGATE=0;
+       break;
+      default:
+       BX_ERROR(("Mode not implemented."));
+       thisctr.next_change_time=0;
+       thisctr.triggerGATE=0;
+       break;
+      }
+    }
+  }
+
+  void pit_82C54::clock_all(Bit32u cycles) {
+    BX_DEBUG(("clock_all:  cycles=%d",cycles));
+    clock_multiple(0,cycles);
+    clock_multiple(1,cycles);
+    clock_multiple(2,cycles);
+  }
+
+  Bit8u pit_82C54::read(Bit8u address) {
+    if(address>MAX_ADDRESS) {
+      BX_ERROR(("Counter address incorrect in data read."));
+    } else if(address==CONTROL_ADDRESS) {
+      BX_DEBUG(("PIT Read: Control Word Register."));
+      //Read from control word register;
+      /* This might be okay.  If so, 0 seems the most logical
+       *  return value from looking at the docs.
+       */
+      BX_ERROR(("Read from control word register not defined."));
+      return 0;
+    } else {
+      //Read from a counter;
+      BX_DEBUG(("PIT Read: Counter %d.",address));
+      counter_type & thisctr=counter[address];
+      if(thisctr.status_latched) {
+       //Latched Status Read;
+       if(thisctr.count_MSB_latched &&
+          (thisctr.read_state==MSByte_multiple) ) {
+         BX_ERROR(("Undefined output when status latched and count half read."));
+       } else {
+         thisctr.status_latched=0;
+         return thisctr.status_latch;
+       }
+      } else {
+       //Latched Count Read;
+       if(thisctr.count_LSB_latched) {
+         //Read Least Significant Byte;
+         if(thisctr.read_state==LSByte_multiple) {
+           BX_DEBUG(("Setting read_state to MSB_mult"));
+           thisctr.read_state=MSByte_multiple;
+         }
+         thisctr.count_LSB_latched=0;
+         return (thisctr.outlatch & 0xFF);
+       } else if(thisctr.count_MSB_latched) {
+         //Read Most Significant Byte;
+         if(thisctr.read_state==MSByte_multiple) {
+           BX_DEBUG(("Setting read_state to LSB_mult"));
+           thisctr.read_state=LSByte_multiple;
+         }
+         thisctr.count_MSB_latched=0;
+         return ((thisctr.outlatch>>8) & 0xFF);
+       } else {
+         //Unlatched Count Read;
+         if(!(thisctr.read_state & 0x1)) {
+           //Read Least Significant Byte;
+           if(thisctr.read_state==LSByte_multiple) {
+             thisctr.read_state=MSByte_multiple;
+             BX_DEBUG(("Setting read_state to MSB_mult"));
+           }
+           return (thisctr.count & 0xFF);
+         } else {
+           //Read Most Significant Byte;
+           if(thisctr.read_state==MSByte_multiple) {
+             BX_DEBUG(("Setting read_state to LSB_mult"));
+             thisctr.read_state=LSByte_multiple;
+           }
+           return ((thisctr.count>>8) & 0xFF);
+         }
+       }
+      }
+    }
+    //Should only get here on errors;
+    return 0;
+  }
+
+  void pit_82C54::write(Bit8u address, Bit8u data) {
+    if(address>MAX_ADDRESS) {
+      BX_ERROR(("Counter address incorrect in data write."));
+    } else if(address==CONTROL_ADDRESS) {
+      Bit8u SC, RW, M, BCD;
+      controlword=data;
+      BX_DEBUG(("Control Word Write."));
+      SC = (controlword>>6) & 0x3;
+      RW = (controlword>>4) & 0x3;
+      M = (controlword>>1) & 0x7;
+      BCD = controlword & 0x1;
+      if(SC == 3) {
+       //READ_BACK command;
+       int i;
+       BX_DEBUG(("READ_BACK command."));
+       for(i=0;i<=MAX_COUNTER;i++) {
+         if((M>>i) & 0x1) {
+           //If we are using this counter;
+           counter_type & thisctr=counter[i];
+           if(!((controlword>>5) & 1)) {
+             //Latch Count;
+             latch_counter(thisctr);
+           }
+           if(!((controlword>>4) & 1)) {
+             //Latch Status;
+             if(thisctr.status_latched) {
+               //Do nothing because latched status has not been read.;
+             } else {
+               thisctr.status_latch=
+                 ((thisctr.OUTpin & 0x1) << 7) |
+                 ((thisctr.null_count & 0x1) << 6) |
+                 ((thisctr.rw_mode & 0x3) << 4) |
+                 ((thisctr.mode & 0x7) << 1) |
+                 (thisctr.bcd_mode&0x1)
+                 ;
+               thisctr.status_latched=1;
+             }
+           }
+         }
+       }
+      } else {
+       counter_type & thisctr = counter[SC];
+       if(!RW) {
+         //Counter Latch command;
+         BX_DEBUG(("Counter Latch command.  SC=%d",SC));
+         latch_counter(thisctr);
+       } else {
+         //Counter Program Command;
+         BX_DEBUG(("Counter Program command.  SC=%d, RW=%d, M=%d, BCD=%d",SC,RW,M,BCD));
+         thisctr.null_count=1;
+         thisctr.count_LSB_latched=0;
+         thisctr.count_MSB_latched=0;
+         thisctr.status_latched=0;
+         thisctr.inlatch=0;
+         thisctr.count_written=0;
+         thisctr.first_pass=1;
+         thisctr.rw_mode=RW;
+         thisctr.bcd_mode=(BCD > 0);
+         thisctr.mode=M;
+         switch(RW) {
+         case 0x1:
+           BX_DEBUG(("Setting read_state to LSB"));
+           thisctr.read_state=LSByte;
+           thisctr.write_state=LSByte;
+           break;
+         case 0x2:
+           BX_DEBUG(("Setting read_state to MSB"));
+           thisctr.read_state=MSByte;
+           thisctr.write_state=MSByte;
+           break;
+         case 0x3:
+           BX_DEBUG(("Setting read_state to LSB_mult"));
+           thisctr.read_state=LSByte_multiple;
+           thisctr.write_state=LSByte_multiple;
+           break;
+         default:
+           BX_ERROR(("RW field invalid in control word write."));
+           break;
+         }
+         //All modes except mode 0 have initial output of 1.;
+         if(M) {
+           set_OUT(thisctr, 1);
+         } else {
+           set_OUT(thisctr, 0);
+         }
+         thisctr.next_change_time=0;
+       }
+      }
+    } else {
+      //Write to counter initial value.
+      counter_type & thisctr = counter[address];
+      BX_DEBUG(("Write Initial Count: counter=%d, count=%d",address,data));
+      switch(thisctr.write_state) {
+      case LSByte_multiple:
+       thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
+       thisctr.write_state=MSByte_multiple;
+       break;
+      case LSByte:
+       thisctr.inlatch=(thisctr.inlatch & (0xFF<<8)) | data;
+       thisctr.null_count=1;
+       thisctr.count_written=1;
+       break;
+      case MSByte_multiple:
+       thisctr.write_state=LSByte_multiple;
+      case MSByte: //shared between MSB_multiple and MSByte
+       thisctr.inlatch=(thisctr.inlatch & 0xFF) | (data<<8);
+       thisctr.null_count=1;
+       thisctr.count_written=1;
+       break;
+      default:
+       BX_ERROR(("write counter in invalid write state."));
+       break;
+      }
+      switch(thisctr.mode) {
+      case 0:
+       if(thisctr.write_state==MSByte_multiple) {
+         set_OUT(thisctr,0);
+       }
+       thisctr.next_change_time=1;
+       break;
+      case 1:
+       if(thisctr.triggerGATE) { //for initial writes, if already saw trigger.
+         thisctr.next_change_time=1;
+       } //Otherwise, no change.
+       break;
+      case 6:
+      case 2:
+       thisctr.next_change_time=1; //FIXME: this could be loosened.
+       break;
+      case 7:
+      case 3:
+       thisctr.next_change_time=1; //FIXME: this could be loosened.
+       break;
+      case 4:
+       thisctr.next_change_time=1;
+       break;
+      case 5:
+       if(thisctr.triggerGATE) { //for initial writes, if already saw trigger.
+         thisctr.next_change_time=1;
+       } //Otherwise, no change.
+       break;
+      }
+    }
+  }
+
+  void pit_82C54::set_GATE(Bit8u cnum, bool data) {
+    if(cnum>MAX_COUNTER) {
+      BX_ERROR(("Counter number incorrect in 82C54 set_GATE"));
+    } else {
+      counter_type & thisctr = counter[cnum];
+      if(!( (thisctr.GATE&&data) || (!(thisctr.GATE||data)) )) {
+        BX_INFO(("Changing GATE %d to: %d",cnum,data));
+       thisctr.GATE=data;
+       if(thisctr.GATE) {
+         thisctr.triggerGATE=1;
+       }
+       switch(thisctr.mode) {
+       case 0:
+         if(data && thisctr.count_written) {
+           if(thisctr.null_count) {
+             thisctr.next_change_time=1;
+           } else {
+             if( (!thisctr.OUTpin) &&
+                 (thisctr.write_state!=MSByte_multiple)
+                 ) {
+                if(thisctr.count_binary==0) {
+                 thisctr.next_change_time=1;
+                } else {
+                 thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+               }
+             } else {
+               thisctr.next_change_time=0;
+             }
+           }
+         } else {
+           if(thisctr.null_count) {
+             thisctr.next_change_time=1;
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+         break;
+       case 1:
+         if(data && thisctr.count_written) { //only triggers cause a change.
+           thisctr.next_change_time=1;
+         }
+         break;
+       case 2:
+         if(!data) {
+           set_OUT(thisctr,1);
+           thisctr.next_change_time=0;
+         } else {
+           if(thisctr.count_written) {
+             thisctr.next_change_time=1;
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+         break;
+       case 3:
+         if(!data) {
+           set_OUT(thisctr,1);
+           thisctr.first_pass=1;
+           thisctr.next_change_time=0;
+         } else {
+           if(thisctr.count_written) {
+             thisctr.next_change_time=1;
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+         break;
+       case 4:
+         if(!thisctr.OUTpin || thisctr.null_count) {
+           thisctr.next_change_time=1;
+         } else {
+           if(data && thisctr.count_written) {
+             if(thisctr.first_pass) {
+                if(thisctr.count_binary==0) {
+                 thisctr.next_change_time=1;
+                } else {
+                 thisctr.next_change_time=thisctr.count_binary & 0xFFFF;
+               }
+             } else {
+               thisctr.next_change_time=0;
+             }
+           } else {
+             thisctr.next_change_time=0;
+           }
+         }
+         break;
+       case 5:
+         if(data && thisctr.count_written) { //only triggers cause a change.
+           thisctr.next_change_time=1;
+         }
+         break;
+       default:
+         break;
+       }
+      }
+    }
+  }
+
+  bool pit_82C54::read_OUT(Bit8u cnum) {
+    if(cnum>MAX_COUNTER) {
+      BX_ERROR(("Counter number incorrect in 82C54 read_OUT"));
+      return 0;
+    } else {
+      return counter[cnum].OUTpin;
+    }
+  }
+
+  bool pit_82C54::read_GATE(Bit8u cnum) {
+    if(cnum>MAX_COUNTER) {
+      BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
+      return 0;
+    } else {
+      return counter[cnum].GATE;
+    }
+  }
+
+Bit32u pit_82C54::get_clock_event_time(Bit8u cnum) {
+  if(cnum>MAX_COUNTER) {
+    BX_ERROR(("Counter number incorrect in 82C54 read_GATE"));
+    return 0;
+  } else {
+    return counter[cnum].next_change_time;
+  }
+}
+
+Bit32u pit_82C54::get_next_event_time(void) {
+  Bit32u out;
+  Bit32u time0=get_clock_event_time(0);
+  Bit32u time1=get_clock_event_time(1);
+  Bit32u time2=get_clock_event_time(2);
+
+  out=time0;
+  if(time1 && (time1<out))
+    out=time1;
+  if(time2 && (time2<out))
+    out=time2;
+  return out;
+}
diff --git a/tools/ioemu/iodev/pit82c54.h b/tools/ioemu/iodev/pit82c54.h
new file mode 100644 (file)
index 0000000..bae2c2b
--- /dev/null
@@ -0,0 +1,134 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit82c54.h,v 1.12 2003/03/02 23:59:11 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/*
+ * Emulator of an Intel 8254/82C54 Programmable Interval Timer.
+ * Greg Alexander <yakovlev@usa.com>
+ *
+ * This code is not yet linked into Bochs, but has been included so
+ * that you can experiment with it.  (bbd)
+ */
+
+#ifndef _PIT_82C54_H_
+#define _PIT_82C54_H_ 1
+
+#include "bochs.h"
+
+
+class pit_82C54 : public logfunctions {
+
+public:
+  //Please do not use these.  They are public because they have to be
+  // to compile on some platforms.  They are not to be used by other
+  // classes.
+
+  enum rw_status {
+    LSByte=0,
+    MSByte=1,
+    LSByte_multiple=2,
+    MSByte_multiple=3
+  };
+
+private:
+
+  enum {
+    MAX_COUNTER=2,
+    MAX_ADDRESS=3,
+    CONTROL_ADDRESS=3,
+    MAX_MODE=5
+  };
+
+  enum real_RW_status {
+    LSB_real=1,
+    MSB_real=2,
+    BOTH_real=3
+  };
+
+  enum problem_type {
+    UNL_2P_READ=1
+  };
+
+  struct counter_type {
+    //Chip IOs;
+    bool GATE; //GATE Input value at end of cycle
+    bool OUTpin; //OUT output this cycle
+
+    //Architected state;
+    Bit32u count; //Counter value this cycle
+    Bit16u outlatch; //Output latch this cycle
+    Bit16u inlatch; //Input latch this cycle
+    Bit8u status_latch;
+
+    //Status Register data;
+    Bit8u rw_mode; //2-bit R/W mode from command word register.
+    Bit8u mode; //3-bit mode from command word register.
+    bool bcd_mode; //1-bit BCD vs. Binary setting.
+    bool null_count; //Null count bit of status register.
+
+    //Latch status data;
+    bool count_LSB_latched;
+    bool count_MSB_latched;
+    bool status_latched;
+
+    //Miscelaneous State;
+    Bit32u count_binary; //Value of the count in binary.
+    bool triggerGATE; //Whether we saw GATE rise this cycle.
+    rw_status write_state; //Read state this cycle
+    rw_status read_state; //Read state this cycle
+    bool count_written; //Whether a count written since programmed
+    bool first_pass; //Whether or not this is the first loaded count.
+    bool state_bit_1; //Miscelaneous state bits.
+    bool state_bit_2;
+    Bit32u next_change_time; //Next time something besides count changes.
+                             //0 means never.
+  };
+
+  counter_type counter[3];
+
+  Bit8u controlword;
+
+  int seen_problems;
+
+  void latch_counter(counter_type & thisctr);
+
+  void set_OUT (counter_type & thisctr, bool data);
+
+  void set_count (counter_type & thisctr, Bit32u data) BX_CPP_AttrRegparmN(2);
+
+  void set_count_to_binary (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
+
+  void set_binary_to_count (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
+
+  void decrement (counter_type & thisctr) BX_CPP_AttrRegparmN(1);
+
+  void decrement_multiple(counter_type & thisctr, Bit32u cycles) BX_CPP_AttrRegparmN(2);
+
+  void clock(Bit8u cnum) BX_CPP_AttrRegparmN(1);
+
+  void print_counter(counter_type & thisctr);
+
+public:
+  void init (void);
+  void reset (unsigned type);
+  pit_82C54 (void);
+
+  void clock_all(Bit32u cycles);
+  void clock_multiple(Bit8u cnum, Bit32u cycles);
+
+  Bit8u read(Bit8u address);
+  void write(Bit8u address, Bit8u data);
+
+  void set_GATE(Bit8u cnum, bool data);
+  bool read_GATE(Bit8u cnum);
+
+  bool read_OUT(Bit8u cnum);
+
+  Bit32u get_clock_event_time(Bit8u cnum);
+  Bit32u get_next_event_time(void);
+
+  void print_cnum(Bit8u cnum);
+
+};
+
+#endif
diff --git a/tools/ioemu/iodev/pit_wrap.cc b/tools/ioemu/iodev/pit_wrap.cc
new file mode 100644 (file)
index 0000000..ae09b3e
--- /dev/null
@@ -0,0 +1,438 @@
+////////////////////////////////////////////////////////////////////////
+// $Id: pit_wrap.cc,v 1.52 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+#include "bochs.h"
+
+#if BX_USE_NEW_PIT
+
+#include "pit_wrap.h"
+
+
+//Important constant #defines:
+#define USEC_PER_SECOND (1000000)
+//1.193181MHz Clock
+#define TICKS_PER_SECOND (1193181)
+
+
+// define a macro to convert floating point numbers into 64-bit integers.
+// In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
+// but it will not convert a 64-bit float into a 64-bit unsigned integer.
+// This macro works around that.
+#define F2I(x)  ((Bit64u)(Bit64s) (x))
+#define I2F(x)  ((double)(Bit64s) (x))
+
+//DEBUG configuration:
+
+//Set up Logging.
+#define LOG_THIS bx_pit.
+
+//A single instance.
+bx_pit_c bx_pit;
+#if BX_USE_PIT_SMF
+#define this (&bx_pit)
+#endif
+
+//Workaround for environments where OUT is defined.
+#ifdef OUT
+#  undef OUT
+#endif
+
+
+//Generic MAX and MIN Functions
+#define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
+#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
+
+
+//USEC_ALPHA is multiplier for the past.
+//USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
+#define USEC_ALPHA ((double)(.8))
+#define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
+#define USEC_ALPHA2 ((double)(.5))
+#define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
+#define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
+
+
+//PIT tick to usec conversion functions:
+//Direct conversions:
+#define TICKS_TO_USEC(a) ( ((a)*USEC_PER_SECOND)/TICKS_PER_SECOND )
+#define USEC_TO_TICKS(a) ( ((a)*TICKS_PER_SECOND)/USEC_PER_SECOND )
+
+
+bx_pit_c::bx_pit_c( void )
+{
+  put("PIT");
+  settype(PITLOG);
+  s.speaker_data_on=0;
+
+  /* 8254 PIT (Programmable Interval Timer) */
+
+  BX_PIT_THIS s.timer_handle[1] = BX_NULL_TIMER_HANDLE;
+  BX_PIT_THIS s.timer_handle[2] = BX_NULL_TIMER_HANDLE;
+  BX_PIT_THIS s.timer_handle[0] = BX_NULL_TIMER_HANDLE;
+}
+
+bx_pit_c::~bx_pit_c( void )
+{
+}
+
+  int
+bx_pit_c::init( void )
+{
+  DEV_register_irq(0, "8254 PIT");
+  DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1);
+  DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1);
+
+  DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1);
+  DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1);
+
+  BX_DEBUG(("pit: starting init"));
+
+  BX_PIT_THIS s.speaker_data_on = 0;
+  BX_PIT_THIS s.refresh_clock_div2 = 0;
+
+  BX_PIT_THIS s.timer.init();
+
+  Bit64u my_time_usec = bx_virt_timer.time_usec();
+
+  if (BX_PIT_THIS s.timer_handle[0] == BX_NULL_TIMER_HANDLE) {
+    BX_PIT_THIS s.timer_handle[0] = bx_virt_timer.register_timer(this, timer_handler, (unsigned) 100 , 1, 1, "pit_wrap");
+  }
+  BX_DEBUG(("pit: RESETting timer."));
+  bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
+  BX_DEBUG(("deactivated timer."));
+  if(BX_PIT_THIS s.timer.get_next_event_time()) {
+    bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], 
+                               (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
+                               0);
+    BX_DEBUG(("activated timer."));
+  }
+  BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
+  BX_PIT_THIS s.last_usec=my_time_usec;
+
+  BX_PIT_THIS s.total_ticks=0;
+  BX_PIT_THIS s.total_usec=0;
+
+  BX_DEBUG(("pit: finished init"));
+
+  BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
+  BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
+  BX_DEBUG(("s.timer.get_next_event_time=%d",BX_PIT_THIS s.timer.get_next_event_time()));
+  BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
+
+  return(1);
+}
+
+  void
+bx_pit_c::reset(unsigned type)
+{
+}
+
+void
+bx_pit_c::timer_handler(void *this_ptr) {
+  bx_pit_c * class_ptr = (bx_pit_c *) this_ptr;
+
+  class_ptr->handle_timer();
+}
+
+void
+bx_pit_c::handle_timer() {
+  Bit64u my_time_usec = bx_virt_timer.time_usec();
+  Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
+  Bit32u time_passed32 = (Bit32u)time_passed;
+
+  BX_DEBUG(("pit: entering timer handler"));
+
+  if(time_passed32) {
+    periodic(time_passed32);
+  }
+  BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
+  if(time_passed ||
+     (BX_PIT_THIS s.last_next_event_time
+      != BX_PIT_THIS s.timer.get_next_event_time())
+     ) {
+    BX_DEBUG(("pit: RESETting timer."));
+    bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
+    BX_DEBUG(("deactivated timer."));
+    if(BX_PIT_THIS s.timer.get_next_event_time()) {
+      bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], 
+                                 (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
+                                 0);
+      BX_DEBUG(("activated timer."));
+    }
+    BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
+  }
+  BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
+  BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
+  BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
+  BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_pit_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+  bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_pit_c::read( Bit32u   address, unsigned int io_len )
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PIT_SMF
+  BX_DEBUG(("pit: entering read handler"));
+
+  handle_timer();
+
+  Bit64u my_time_usec = bx_virt_timer.time_usec();
+
+  if (bx_dbg.pit)
+    BX_INFO(("pit: io read from port %04x", (unsigned) address));
+
+  switch (address) {
+
+    case 0x40: /* timer 0 - system ticks */
+      return(BX_PIT_THIS s.timer.read(0));
+      break;
+    case 0x41: /* timer 1 read */
+      return(BX_PIT_THIS s.timer.read(1));
+      break;
+    case 0x42: /* timer 2 read */
+      return(BX_PIT_THIS s.timer.read(2));
+      break;
+    case 0x43: /* timer 1 read */
+      return(BX_PIT_THIS s.timer.read(3));
+      break;
+
+    case 0x61:
+      /* AT, port 61h */
+      BX_PIT_THIS s.refresh_clock_div2 = (bx_bool)((my_time_usec / 15) & 1);
+      return( (BX_PIT_THIS s.timer.read_OUT(2)<<5) |
+              (BX_PIT_THIS s.refresh_clock_div2<<4) |
+              (BX_PIT_THIS s.speaker_data_on<<1) |
+              (BX_PIT_THIS s.timer.read_GATE(2)?1:0) );
+      break;
+
+    default:
+      BX_PANIC(("pit: unsupported io read from port %04x", address));
+  }
+  return(0); /* keep compiler happy */
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_pit_c::write_handler(void *this_ptr, Bit32u address, Bit32u dvalue, unsigned io_len)
+{
+#if !BX_USE_PIT_SMF
+  bx_pit_c *class_ptr = (bx_pit_c *) this_ptr;
+
+  class_ptr->write(address, dvalue, io_len);
+}
+
+  void
+bx_pit_c::write( Bit32u   address, Bit32u   dvalue,
+                unsigned int io_len )
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_PIT_SMF
+  Bit8u   value;
+  Bit64u my_time_usec = bx_virt_timer.time_usec();
+  Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec;
+  Bit32u time_passed32 = (Bit32u)time_passed;
+
+  BX_DEBUG(("pit: entering write handler"));
+
+  if(time_passed32) {
+    periodic(time_passed32);
+  }
+  BX_PIT_THIS s.last_usec=BX_PIT_THIS s.last_usec + time_passed;
+
+  value = (Bit8u  ) dvalue;
+
+  if (bx_dbg.pit)
+    BX_INFO(("pit: write to port %04x = %02x",
+      (unsigned) address, (unsigned) value));
+
+  switch (address) {
+    case 0x40: /* timer 0: write count register */
+      BX_PIT_THIS s.timer.write(0,value);
+      break;
+
+    case 0x41: /* timer 1: write count register */
+      BX_PIT_THIS s.timer.write( 1,value );
+      break;
+
+    case 0x42: /* timer 2: write count register */
+      BX_PIT_THIS s.timer.write( 2,value );
+      break;
+
+    case 0x43: /* timer 0-2 mode control */
+      BX_PIT_THIS s.timer.write( 3,value );
+      break;
+
+    case 0x61:
+      BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01;
+/*??? only on AT+ */
+      BX_PIT_THIS s.timer.set_GATE(2, value & 0x01);
+#if BX_CPU_LEVEL < 2
+      /* ??? XT: */
+      bx_kbd_port61h_write(value);
+#endif
+      break;
+
+    default:
+      BX_PANIC(("pit: unsupported io write to port %04x = %02x",
+        (unsigned) address, (unsigned) value));
+  }
+
+  if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+    DEV_pic_raise_irq(0);
+  } else {
+    DEV_pic_lower_irq(0);
+  }
+
+  if(time_passed ||
+     (BX_PIT_THIS s.last_next_event_time
+      != BX_PIT_THIS s.timer.get_next_event_time())
+     ) {
+    BX_DEBUG(("pit: RESETting timer."));
+    bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]);
+    BX_DEBUG(("deactivated timer."));
+    if(BX_PIT_THIS s.timer.get_next_event_time()) {
+      bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], 
+                                 (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())),
+                                 0);
+      BX_DEBUG(("activated timer."));
+    }
+    BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time();
+  }
+  BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec));
+  BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0]));
+  BX_DEBUG(("s.timer.get_next_event_time=%x",BX_PIT_THIS s.timer.get_next_event_time()));
+  BX_DEBUG(("s.last_next_event_time=%d",BX_PIT_THIS s.last_next_event_time));
+
+}
+
+
+
+
+  int
+bx_pit_c::SaveState( class state_file *fd )
+{
+  fd->write_check ("8254 start");
+  fd->write (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+  fd->write_check ("8254 end");
+  return(0);
+}
+
+
+  int
+bx_pit_c::LoadState( class state_file *fd )
+{
+  fd->read_check ("8254 start");
+  fd->read (&BX_PIT_THIS s, sizeof (BX_PIT_THIS s));
+  fd->read_check ("8254 end");
+  return(0);
+}
+
+
+#if 0
+  void
+bx_kbd_port61h_write(Bit8u   value)
+{
+//  PcError("KBD_PORT61H_WRITE(): not implemented yet");
+  UNUSED( value );
+}
+#endif
+
+
+  bx_bool
+bx_pit_c::periodic( Bit32u   usec_delta )
+{
+  bx_bool prev_timer0_out = BX_PIT_THIS s.timer.read_OUT(0);
+  bx_bool want_interrupt = 0;
+  Bit32u ticks_delta = 0;
+
+#ifdef BX_SCHEDULED_DIE_TIME
+  if (bx_pc_system.time_ticks() > BX_SCHEDULED_DIE_TIME) {
+    BX_ERROR (("ticks exceeded scheduled die time, quitting"));
+    BX_EXIT (2);
+  }
+#endif
+
+  BX_PIT_THIS s.total_usec += usec_delta;
+  ticks_delta=(Bit32u)((USEC_TO_TICKS((Bit64u)(BX_PIT_THIS s.total_usec)))-BX_PIT_THIS s.total_ticks);
+  BX_PIT_THIS s.total_ticks += ticks_delta;
+
+  while ((BX_PIT_THIS s.total_ticks >= TICKS_PER_SECOND) && (BX_PIT_THIS s.total_usec >= USEC_PER_SECOND)) {
+    BX_PIT_THIS s.total_ticks -= TICKS_PER_SECOND;
+    BX_PIT_THIS s.total_usec  -= USEC_PER_SECOND;
+  }
+
+  while(ticks_delta>0) {
+    Bit32u maxchange=BX_PIT_THIS s.timer.get_next_event_time();
+    Bit32u timedelta=maxchange;
+    if((maxchange==0) || (maxchange>ticks_delta)) {
+      timedelta=ticks_delta;
+    }
+    BX_PIT_THIS s.timer.clock_all(timedelta);
+    if ( (prev_timer0_out==0) ) {
+      if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+       DEV_pic_raise_irq(0);
+        prev_timer0_out=1;
+      }
+    } else {
+      if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
+       DEV_pic_lower_irq(0);
+        prev_timer0_out=0;
+      }
+    }
+    prev_timer0_out=BX_PIT_THIS s.timer.read_OUT(0);
+    ticks_delta-=timedelta;
+  }
+
+  return(want_interrupt);
+}
+
+#endif // #if BX_USE_NEW_PIT
diff --git a/tools/ioemu/iodev/pit_wrap.h b/tools/ioemu/iodev/pit_wrap.h
new file mode 100644 (file)
index 0000000..e45e1e6
--- /dev/null
@@ -0,0 +1,104 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: pit_wrap.h,v 1.17 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#ifndef _BX_PIT_WRAP_H
+#define _BX_PIT_WRAP_H
+
+#include "bochs.h"
+
+#if BX_USE_NEW_PIT
+
+#include "pit82c54.h"
+
+#if BX_USE_PIT_SMF
+#  define BX_PIT_SMF  static
+#  define BX_PIT_THIS bx_pit.
+#else
+#  define BX_PIT_SMF
+#  define BX_PIT_THIS this->
+#endif
+
+#ifdef OUT
+#  undef OUT
+#endif
+
+class bx_pit_c : public logfunctions {
+public:
+  bx_pit_c( void );
+  ~bx_pit_c( void );
+  BX_PIT_SMF int init( void );
+  BX_PIT_SMF void reset( unsigned type);
+  BX_PIT_SMF bx_bool periodic( Bit32u   usec_delta );
+
+  BX_PIT_SMF int SaveState( class state_file *fd );
+  BX_PIT_SMF int LoadState( class state_file *fd );
+
+private:
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_PIT_SMF
+  Bit32u   read( Bit32u   addr, unsigned int len );
+  void write( Bit32u   addr, Bit32u   Value, unsigned int len );
+#endif
+
+  struct s_type {
+    pit_82C54 timer;
+    Bit8u   speaker_data_on;
+    bx_bool refresh_clock_div2;
+    int  timer_handle[3];
+    Bit64u last_usec;
+    Bit32u last_next_event_time;
+    Bit64u total_ticks;
+    Bit64u usec_per_second;
+    Bit64u ticks_per_second;
+    Bit64u total_sec;
+    Bit64u last_time;
+    Bit64u last_sec_usec;
+    Bit64u max_ticks;
+    Bit64u stored_delta;
+    Bit64u total_usec;
+    Bit64u em_last_realtime;
+    Bit64u last_realtime_delta;
+    Bit64u last_realtime_ticks;
+    } s;
+
+  static void timer_handler(void *this_ptr);
+  BX_PIT_SMF void handle_timer();
+
+  BX_PIT_SMF void  write_count_reg( Bit8u   value, unsigned timerid );
+  BX_PIT_SMF Bit8u read_counter( unsigned timerid );
+  BX_PIT_SMF void  latch( unsigned timerid );
+  BX_PIT_SMF void  set_GATE(unsigned pit_id, unsigned value);
+  BX_PIT_SMF void  start(unsigned timerid);
+
+  BX_PIT_SMF void  second_update_data(void);
+};
+
+extern bx_pit_c bx_pit;
+
+#endif  // #if BX_USE_NEW_PIT
+#endif  // #ifndef _BX_PIT_WRAP_H
diff --git a/tools/ioemu/iodev/plugin.cc b/tools/ioemu/iodev/plugin.cc
new file mode 100644 (file)
index 0000000..136065d
--- /dev/null
@@ -0,0 +1,554 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: plugin.cc,v 1.8 2003/07/31 12:04:47 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+// This file defines the plugin and plugin-device registration functions and
+// the device registration functions.  It handles dynamic loading of modules,
+// using the LTDL library for cross-platform support.
+//
+// This file is based on the plugin.c file from plex86, but with significant
+// changes to make it work in Bochs.
+// Plex86 is Copyright (C) 1999-2000  The plex86 developers team
+//
+/////////////////////////////////////////////////////////////////////////
+
+#include "bochs.h"
+#include "plugin.h"
+
+#define LOG_THIS genlog->
+
+#define PLUGIN_INIT_FMT_STRING  "lib%s_LTX_plugin_init"
+#define PLUGIN_FINI_FMT_STRING  "lib%s_LTX_plugin_fini"
+#define PLUGIN_PATH ""
+
+#ifndef WIN32
+#define PLUGIN_FILENAME_FORMAT "libbx_%s.la"
+#else
+#define PLUGIN_FILENAME_FORMAT "bx_%s.dll"
+#endif
+
+
+
+void  (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0;
+void  (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 0;
+
+void  (* pluginResetSignal)(unsigned sig) = 0;
+
+void (*pluginSetHRQ)(unsigned val) = 0;
+void (*pluginSetHRQHackCallback)( void (*callback)(void) ) = 0;
+
+int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+                            unsigned base, const char *name, Bit8u mask) = 0;
+int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+                             unsigned base, const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+                            const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+                             const char *name, Bit8u mask) = 0;
+int (*pluginRegisterTimer)(void *this_ptr, void (*funct)(void *),
+                       Bit32u useconds, bx_bool continuous, 
+                       bx_bool active, const char* name) = 0;
+void (*pluginActivateTimer)(unsigned id, Bit32u usec, bx_bool continuous) = 0;
+
+void (*pluginHRQHackCallback)(void);
+unsigned pluginHRQ = 0;
+
+plugin_t *plugins = NULL;      /* Head of the linked list of plugins  */
+#if BX_PLUGINS
+static void plugin_init_one(plugin_t *plugin);
+#endif
+
+device_t *devices = NULL;      /* Head of the linked list of registered devices  */
+
+plugin_t *current_plugin_context = NULL;
+
+/************************************************************************/
+/* Builtins declarations                                                */
+/************************************************************************/
+
+  static void  
+builtinRegisterIRQ(unsigned irq, const char* name) 
+{
+#if 0
+  pluginlog->panic("builtinRegisterIRQ called, no pic plugin loaded?");
+#else
+  bx_devices.register_irq(irq, name);
+#endif
+}
+
+  static void  
+builtinUnregisterIRQ(unsigned irq, const char* name)
+{
+#if 0
+  pluginlog->panic("builtinUnregisterIRQ called, no pic plugin loaded?");
+#else
+  bx_devices.unregister_irq(irq, name);
+#endif
+}
+
+  static void
+builtinSetHRQ(unsigned val)
+{
+#if 0
+  pluginlog->panic("builtinSetHRQ called, no plugin loaded?");
+#else
+  pluginHRQ = val;
+#endif
+}
+
+  static void
+builtinSetHRQHackCallback( void (*callback)(void) )
+{
+#if 0
+  pluginlog->panic("builtinSetHRQHackCallback called, no plugin loaded?");
+#else
+  pluginHRQHackCallback = callback;
+#endif
+}
+
+  static void
+builtinResetSignal( unsigned )
+{
+  pluginlog->panic("builtinResetSignal called, no plugin loaded?");
+}
+
+  static int
+builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback,
+                            unsigned base, const char *name, Bit8u mask)
+{
+  BX_ASSERT (mask<8);
+  bx_devices.register_io_read_handler (thisPtr, callback, base, name, mask);
+  pluginlog->ldebug("plugin %s registered I/O read address at %04x", name, base);
+  return 0;
+}
+
+  static int
+builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
+                             unsigned base, const char *name, Bit8u mask)
+{
+  BX_ASSERT (mask<8);
+  bx_devices.register_io_write_handler (thisPtr, callback, base, name, mask);
+  pluginlog->ldebug("plugin %s registered I/O write address at %04x", name, base);
+  return 0;
+}
+
+  static int
+builtinRegisterDefaultIOReadHandler(void *thisPtr, ioReadHandler_t callback,
+                            const char *name, Bit8u mask)
+{
+  BX_ASSERT (mask<8);
+  bx_devices.register_default_io_read_handler (thisPtr, callback, name, mask);
+  pluginlog->ldebug("plugin %s registered default I/O read ", name);
+  return 0;
+}
+
+  static int
+builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
+                             const char *name, Bit8u mask)
+{
+  BX_ASSERT (mask<8);
+  bx_devices.register_default_io_write_handler (thisPtr, callback, name, mask);
+  pluginlog->ldebug("plugin %s registered default I/O write ", name);
+  return 0;
+}
+
+  static int
+builtinRegisterTimer(void *this_ptr, void (*funct)(void *),
+                       Bit32u useconds, bx_bool continuous, 
+                       bx_bool active, const char* name)
+{
+  int id = bx_pc_system.register_timer (this_ptr, funct, useconds, continuous, active, name);
+  pluginlog->ldebug("plugin %s registered timer %d", name, id);
+  return id;
+}
+
+  static void
+builtinActivateTimer(unsigned id, Bit32u usec, bx_bool continuous)
+{
+  bx_pc_system.activate_timer (id, usec, continuous);
+  pluginlog->ldebug("plugin activated timer %d", id);
+}
+
+#if BX_PLUGINS
+/************************************************************************/
+/* Plugin initialization / deinitialization                             */
+/************************************************************************/
+
+  void
+plugin_init_all (void)
+{
+    plugin_t *plugin;
+
+    pluginlog->info("Initializing plugins");
+
+    for (plugin = plugins; plugin; plugin = plugin->next)
+    {
+        char *arg_ptr = plugin->args;
+
+        /* process the command line */
+        plugin->argc = 0;
+        while (plugin->argc < MAX_ARGC)
+        {
+            while (*arg_ptr && isspace (*arg_ptr))
+                arg_ptr++;
+
+            if (!*arg_ptr)
+                break;
+            plugin->argv[plugin->argc++] = arg_ptr;
+
+            while (*arg_ptr && !isspace (*arg_ptr))
+                arg_ptr++;
+
+            if (!*arg_ptr)
+                break;
+            *arg_ptr++ = '\0';
+        }
+
+        /* initialize the plugin */
+        if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
+        {
+            pluginlog->panic("Plugin initialization failed for %s", plugin->name);
+            plugin_abort();
+        }
+
+        plugin->initialized = 1;
+    }
+
+    return;
+}
+
+void
+plugin_init_one(plugin_t *plugin)
+{
+        char *arg_ptr = plugin->args;
+        /* process the command line */
+        plugin->argc = 0;
+        while (plugin->argc < MAX_ARGC)
+        {
+            while (*arg_ptr && isspace (*arg_ptr))
+                arg_ptr++;
+            if (!*arg_ptr)
+                break;
+            plugin->argv[plugin->argc++] = arg_ptr;
+            while (*arg_ptr && !isspace (*arg_ptr))
+                arg_ptr++;
+            if (!*arg_ptr)
+                break;
+            *arg_ptr++ = '\0';
+        }
+        /* initialize the plugin */
+        if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
+        {
+            pluginlog->info("Plugin initialization failed for %s", plugin->name);
+            plugin_abort();
+        }
+        plugin->initialized = 1;
+}
+
+
+  plugin_t *
+plugin_unload(plugin_t *plugin)
+{
+    plugin_t *dead_plug;
+
+    if (plugin->initialized)
+        plugin->plugin_fini ();
+
+    lt_dlclose (plugin->handle);
+    free (plugin->name);
+    free (plugin->args);
+
+    dead_plug = plugin;
+    plugin = plugin->next;
+    free (dead_plug);
+
+    return plugin;
+}
+
+
+void
+plugin_fini_all (void)
+{
+    plugin_t *plugin;
+
+    for (plugin = plugins; plugin; plugin = plugin_unload (plugin));
+
+    return;
+}
+
+  void
+plugin_load (char *name, char *args, plugintype_t type)
+{
+    plugin_t *plugin;
+
+    plugin = (plugin_t *)malloc (sizeof (plugin_t));
+    if (!plugin)
+    {
+      BX_PANIC (("malloc plugin_t failed"));
+    }
+
+    plugin->type = type;
+    plugin->name = name;
+    plugin->args = args;
+    plugin->initialized = 0;
+       
+       char plugin_filename[BX_PATHNAME_LEN], buf[BX_PATHNAME_LEN];
+       sprintf (buf, PLUGIN_FILENAME_FORMAT, name);
+       sprintf(plugin_filename, "%s%s", PLUGIN_PATH, buf);
+
+    // Set context so that any devices that the plugin registers will
+    // be able to see which plugin created them.  The registration will
+    // be called from either dlopen (global constructors) or plugin_init.
+    BX_ASSERT (current_plugin_context == NULL);
+    current_plugin_context = plugin;
+    plugin->handle = lt_dlopen (plugin_filename);
+    BX_INFO (("lt_dlhandle is %p", plugin->handle));
+    if (!plugin->handle)
+    {
+      current_plugin_context = NULL;
+      BX_PANIC (("dlopen failed for module '%s': %s", name, lt_dlerror ()));
+      free (plugin);
+      return;
+    }
+
+       sprintf (buf, PLUGIN_INIT_FMT_STRING, name);
+    plugin->plugin_init =  
+      (int  (*)(struct _plugin_t *, enum plugintype_t, int, char *[])) /* monster typecast */
+      lt_dlsym (plugin->handle, buf);
+    if (plugin->plugin_init == NULL) {
+        pluginlog->panic("could not find plugin_init: %s", lt_dlerror ());
+        plugin_abort ();
+    }
+
+       sprintf (buf, PLUGIN_FINI_FMT_STRING, name);
+    plugin->plugin_fini = (void (*)(void)) lt_dlsym (plugin->handle, buf);
+    if (plugin->plugin_init == NULL) {
+        pluginlog->panic("could not find plugin_fini: %s", lt_dlerror ());
+        plugin_abort ();
+    }
+    pluginlog->info("loaded plugin %s",plugin_filename);
+
+
+    /* Insert plugin at the _end_ of the plugin linked list. */
+    plugin->next = NULL;
+
+    if (!plugins)
+    {
+        /* Empty list, this become the first entry. */
+        plugins = plugin;
+    }
+    else
+    {
+        /* Non-empty list.  Add to end. */
+        plugin_t *temp = plugins;
+
+        while (temp->next)
+            temp = temp->next;
+
+        temp->next = plugin;
+    }
+
+    plugin_init_one(plugin);
+
+    // check that context didn't change.  This should only happen if we
+    // need a reentrant plugin_load.
+    BX_ASSERT (current_plugin_context == plugin);
+    current_plugin_context = NULL;
+
+    return;
+}
+
+void
+plugin_abort (void)
+{
+    pluginlog->panic("plugin load aborted");
+}
+
+#endif   /* end of #if BX_PLUGINS */
+
+/************************************************************************/
+/* Plugin system: initialisation of plugins entry points                */
+/************************************************************************/
+
+  void
+plugin_startup(void)
+{
+  pluginRegisterIRQ = builtinRegisterIRQ;
+  pluginUnregisterIRQ = builtinUnregisterIRQ;
+
+  pluginResetSignal = builtinResetSignal;
+
+  pluginSetHRQHackCallback = builtinSetHRQHackCallback;
+  pluginSetHRQ = builtinSetHRQ;
+  
+  pluginRegisterIOReadHandler = builtinRegisterIOReadHandler;
+  pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler;
+
+  pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler;
+  pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler;
+
+  pluginRegisterTimer = builtinRegisterTimer;
+  pluginActivateTimer = builtinActivateTimer;
+
+#if BX_PLUGINS
+  pluginlog = new logfunctions();
+  pluginlog->put("PLGIN");
+  pluginlog->settype(PLUGINLOG);
+  int status = lt_dlinit ();
+  if (status != 0) {
+    BX_ERROR (("initialization error in ltdl library (for loading plugins)"));
+    BX_PANIC (("error message was: %s", lt_dlerror ()));
+  }
+#endif
+}
+
+
+/************************************************************************/
+/* Plugin system: Device registration                                   */
+/************************************************************************/
+
+void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *devmodel, char *name)
+{
+    device_t *device;
+
+    device = (device_t *)malloc (sizeof (device_t));
+    if (!device)
+    {
+        pluginlog->panic("can't allocate device_t");
+    }
+
+    device->name = name;
+    BX_ASSERT (devmodel != NULL);
+    device->devmodel = devmodel;
+    device->plugin = plugin;  // this can be NULL
+    device->use_devmodel_interface = 1;
+    device->device_init_mem = NULL;  // maybe should use 1 to detect any use?
+    device->device_init_dev = NULL;
+    device->device_reset = NULL;
+    device->device_load_state = NULL;
+    device->device_save_state = NULL;
+    device->next = NULL;
+
+    // Don't add every kind of device to the list.
+    switch (type) {
+      case PLUGTYPE_CORE:
+       // Core devices are present whether or not we are using plugins, so
+       // they are managed by the same code in iodev/devices.cc whether
+       // plugins are on or off.  
+       return; // Do not add core devices to the devices list.
+      case PLUGTYPE_OPTIONAL:
+      case PLUGTYPE_USER:
+      default:
+       // The plugin system will manage optional and user devices only.
+       break;
+    }
+
+    if (!devices)
+    {
+        /* Empty list, this become the first entry. */
+        devices = device;
+    }
+    else
+    {
+        /* Non-empty list.  Add to end. */
+        device_t *temp = devices;
+
+        while (temp->next)
+            temp = temp->next;
+
+        temp->next = device;
+    }
+}
+
+/************************************************************************/
+/* Plugin system: Check if a plugin is loaded                           */
+/************************************************************************/
+
+bx_bool pluginDevicePresent(char *name)
+{
+    device_t *device;
+
+    for (device = devices; device; device = device->next)
+    {
+      if (strcmp(device->name,name)==0) return true;
+    }
+
+    return false;
+}
+
+#if BX_PLUGINS
+/************************************************************************/
+/* Plugin system: Load one plugin                                       */
+/************************************************************************/
+
+int bx_load_plugin (const char *name, plugintype_t type)
+{
+  char *namecopy = new char[1+strlen(name)];
+  strcpy (namecopy, name);
+  plugin_load (namecopy, "", type);
+  return 0;
+}
+#endif   /* end of #if BX_PLUGINS */
+
+/*************************************************************************/
+/* Plugin system: Execute init function of all registered plugin-devices */
+/*************************************************************************/
+
+void bx_init_plugins()
+{
+    device_t *device;
+
+    // two loops
+    for (device = devices; device; device = device->next)
+    {
+      if (!device->use_devmodel_interface) {
+        if (device->device_init_mem != NULL) {
+            pluginlog->info("init_mem of '%s' plugin device by function pointer",device->name);
+            device->device_init_mem(BX_MEM(0));
+       }
+      } else {
+       pluginlog->info("init_mem of '%s' plugin device by virtual method",device->name);
+       device->devmodel->init_mem (BX_MEM(0));
+      }
+    }
+
+    for (device = devices; device; device = device->next)
+    {
+      if (!device->use_devmodel_interface) {
+        if (device->device_init_dev != NULL) {
+            pluginlog->info("init_dev of '%s' plugin device by function pointer",device->name);
+            device->device_init_dev();
+       }
+      } else {
+       pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
+       device->devmodel->init ();
+      }
+    } 
+}
+
+/**************************************************************************/
+/* Plugin system: Execute reset function of all registered plugin-devices */
+/**************************************************************************/
+
+void bx_reset_plugins(unsigned signal)
+{
+    device_t *device;
+    for (device = devices; device; device = device->next)
+    {
+      if (!device->use_devmodel_interface) {
+        if (device->device_reset != NULL) {
+            pluginlog->info("reset of '%s' plugin device by function pointer",device->name);
+            device->device_reset(signal);
+        }
+      } else {
+       pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
+       device->devmodel->reset (signal);
+      }
+    }
+}
diff --git a/tools/ioemu/iodev/scancodes.cc b/tools/ioemu/iodev/scancodes.cc
new file mode 100644 (file)
index 0000000..63efed4
--- /dev/null
@@ -0,0 +1,770 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scancodes.cc,v 1.5 2002/10/24 21:07:51 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#include "scancodes.h"
+
+unsigned char translation8042[256] = {
+  0xff,0x43,0x41,0x3f,0x3d,0x3b,0x3c,0x58,0x64,0x44,0x42,0x40,0x3e,0x0f,0x29,0x59,
+  0x65,0x38,0x2a,0x70,0x1d,0x10,0x02,0x5a,0x66,0x71,0x2c,0x1f,0x1e,0x11,0x03,0x5b,
+  0x67,0x2e,0x2d,0x20,0x12,0x05,0x04,0x5c,0x68,0x39,0x2f,0x21,0x14,0x13,0x06,0x5d,
+  0x69,0x31,0x30,0x23,0x22,0x15,0x07,0x5e,0x6a,0x72,0x32,0x24,0x16,0x08,0x09,0x5f,
+  0x6b,0x33,0x25,0x17,0x18,0x0b,0x0a,0x60,0x6c,0x34,0x35,0x26,0x27,0x19,0x0c,0x61,
+  0x6d,0x73,0x28,0x74,0x1a,0x0d,0x62,0x6e,0x3a,0x36,0x1c,0x1b,0x75,0x2b,0x63,0x76,
+  0x55,0x56,0x77,0x78,0x79,0x7a,0x0e,0x7b,0x7c,0x4f,0x7d,0x4b,0x47,0x7e,0x7f,0x6f,
+  0x52,0x53,0x50,0x4c,0x4d,0x48,0x01,0x45,0x57,0x4e,0x51,0x4a,0x37,0x49,0x46,0x54,
+  0x80,0x81,0x82,0x41,0x54,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+  0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+  0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+  0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+  0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+  0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+  };
+
+
+// Definition of scancodes make and break, 
+// for each set (mf1/xt , mf2/at , mf3/ps2)
+// The table must be in BX_KEY order
+//
+scancode scancodes[BX_KEY_NBKEYS][3] =
+{
+ { // BX_KEY_CTRL_L ( ibm 58)
+   { "\x1D" , "\x9D" },
+   { "\x14" , "\xF0\x14" },
+   { "\x11" , "\xF0\x11" },
+ },
+
+ { // BX_KEY_SHIFT_L ( ibm 44)
+   { "\x2A" , "\xAA" },
+   { "\x12" , "\xF0\x12" },
+   { "\x12" , "\xF0\x12" },
+ },
+
+ { // BX_KEY_F1 ( ibm 112 )
+   { "\x3B" , "\xBB" },
+   { "\x05" , "\xF0\x05" },
+   { "\x07" , "\xF0\x07" },
+ },
+
+ { // BX_KEY_F2 ( ibm 113 ) 
+   { "\x3C" , "\xBC" },
+   { "\x06" , "\xF0\x06" },
+   { "\x0F" , "\xF0\x0F" },
+ },
+
+ { // BX_KEY_F3 ( ibm 114 ) 
+   { "\x3D" , "\xBD" },
+   { "\x04" , "\xF0\x04" },
+   { "\x17" , "\xF0\x17" },
+ },
+
+ { // BX_KEY_F4 ( ibm 115 ) 
+   { "\x3E" , "\xBE" },
+   { "\x0C" , "\xF0\x0C" },
+   { "\x1F" , "\xF0\x1F" },
+ },
+
+ { // BX_KEY_F5 ( ibm 116 ) 
+   { "\x3F" , "\xBF" },
+   { "\x03" , "\xF0\x03" },
+   { "\x27" , "\xF0\x27" },
+ },
+
+ { // BX_KEY_F6 ( ibm 117 ) 
+   { "\x40" , "\xC0" },
+   { "\x0B" , "\xF0\x0B" },
+   { "\x2F" , "\xF0\x2F" },
+ },
+
+ { // BX_KEY_F7 ( ibm 118 ) 
+   { "\x41" , "\xC1" },
+   { "\x83" , "\xF0\x83" },
+   { "\x37" , "\xF0\x37" },
+},
+
+ { // BX_KEY_F8 ( ibm 119 ) 
+   { "\x42" , "\xC2" },
+   { "\x0A" , "\xF0\x0A" },
+   { "\x3F" , "\xF0\x3F" },
+ },
+
+ { // BX_KEY_F9 ( ibm 120 ) 
+   { "\x43" , "\xC3" },
+   { "\x01" , "\xF0\x01" },
+   { "\x47" , "\xF0\x47" },
+ },
+
+ { // BX_KEY_F10 ( ibm 121 ) 
+   { "\x44" , "\xC4" },
+   { "\x09" , "\xF0\x09" },
+   { "\x4F" , "\xF0\x4F" },
+ },
+
+ { // BX_KEY_F11 ( ibm 122 ) 
+   { "\x57" , "\xD7" },
+   { "\x78" , "\xF0\x78" },
+   { "\x56" , "\xF0\x56" },
+ },
+
+ { // BX_KEY_F12 ( ibm 123 ) 
+   { "\x58" , "\xD8" },
+   { "\x07" , "\xF0\x07" },
+   { "\x5E" , "\xF0\x5E" },
+ },
+
+ { // BX_KEY_CTRL_R ( ibm 64 ) 
+   { "\xE0\x1D" , "\xE0\x9D" },
+   { "\xE0\x14" , "\xE0\xF0\x14" },
+   { "\x58" ,     "\xF0x58" },
+ },
+
+ { // BX_KEY_SHIFT_R ( ibm 57 ) 
+   { "\x36" , "\xB6" },
+   { "\x59" , "\xF0\x59" },
+   { "\x59" , "\xF0\x59" },
+ },
+
+ { // BX_KEY_CAPS_LOCK ( ibm 30 ) 
+   { "\x3A" , "\xBA" },
+   { "\x58" , "\xF0\x58" },
+   { "\x14" , "\xF0\x14" },
+ },
+
+ { // BX_KEY_NUM_LOCK ( ibm 90 ) 
+   { "\x45" , "\xC5" },
+   { "\x77" , "\xF0\x77" },
+   { "\x76" , "\xF0\x76" },
+ },
+
+ { // BX_KEY_ALT_L ( ibm 60 ) 
+   { "\x38" , "\xB8" },
+   { "\x11" , "\xF0\x11" },
+   { "\x19" , "\xF0\x19" },
+ },
+
+ { // BX_KEY_ALT_R ( ibm 62 ) 
+   { "\xE0\x38" , "\xE0\xB8" },
+   { "\xE0\x11" , "\xE0\xF0\x11" },
+   { "\x39" ,     "\xF0\x39" },
+ },
+
+ { // BX_KEY_A ( ibm 31 ) 
+   { "\x1E" , "\x9E" },
+   { "\x1C" , "\xF0\x1C" },
+   { "\x1C" , "\xF0\x1C" },
+ },
+
+ { // BX_KEY_B ( ibm 50 ) 
+   { "\x30" , "\xB0" },
+   { "\x32" , "\xF0\x32" },
+   { "\x32" , "\xF0\x32" },
+ },
+
+ { // BX_KEY_C ( ibm 48 ) 
+   { "\x2E" , "\xAE" },
+   { "\x21" , "\xF0\x21" },
+   { "\x21" , "\xF0\x21" },
+ },
+
+ { // BX_KEY_D ( ibm 33 ) 
+   { "\x20" , "\xA0" },
+   { "\x23" , "\xF0\x23" },
+   { "\x23" , "\xF0\x23" },
+ },
+
+ { // BX_KEY_E ( ibm 19 ) 
+   { "\x12" , "\x92" },
+   { "\x24" , "\xF0\x24" },
+   { "\x24" , "\xF0\x24" },
+ },
+
+ { // BX_KEY_F ( ibm 34 ) 
+   { "\x21" , "\xA1" },
+   { "\x2B" , "\xF0\x2B" },
+   { "\x2B" , "\xF0\x2B" },
+ },
+
+ { // BX_KEY_G ( ibm 35 ) 
+   { "\x22" , "\xA2" },
+   { "\x34" , "\xF0\x34" },
+   { "\x34" , "\xF0\x34" },
+ },
+
+ { // BX_KEY_H ( ibm 36 ) 
+   { "\x23" , "\xA3" },
+   { "\x33" , "\xF0\x33" },
+   { "\x33" , "\xF0\x33" },
+ },
+
+ { // BX_KEY_I ( ibm 24 ) 
+   { "\x17" , "\x97" },
+   { "\x43" , "\xF0\x43" },
+   { "\x43" , "\xF0\x43" },
+ },
+
+ { // BX_KEY_J ( ibm 37 ) 
+   { "\x24" , "\xA4" },
+   { "\x3B" , "\xF0\x3B" },
+   { "\x3B" , "\xF0\x3B" },
+ },
+
+ { // BX_KEY_K ( ibm 38 ) 
+   { "\x25" , "\xA5" },
+   { "\x42" , "\xF0\x42" },
+   { "\x42" , "\xF0\x42" },
+ },
+
+ { // BX_KEY_L ( ibm 39 ) 
+   { "\x26" , "\xA6" },
+   { "\x4B" , "\xF0\x4B" },
+   { "\x4B" , "\xF0\x4B" },
+ },
+
+ { // BX_KEY_M ( ibm 52 ) 
+   { "\x32" , "\xB2" },
+   { "\x3A" , "\xF0\x3A" },
+   { "\x3A" , "\xF0\x3A" },
+ },
+
+ { // BX_KEY_N ( ibm 51 ) 
+   { "\x31" , "\xB1" },
+   { "\x31" , "\xF0\x31" },
+   { "\x31" , "\xF0\x31" },
+ },
+
+ { // BX_KEY_O ( ibm 25 ) 
+   { "\x18" , "\x98" },
+   { "\x44" , "\xF0\x44" },
+   { "\x44" , "\xF0\x44" },
+ },
+
+ { // BX_KEY_P ( ibm 26 ) 
+   { "\x19" , "\x99" },
+   { "\x4D" , "\xF0\x4D" },
+   { "\x4D" , "\xF0\x4D" },
+ },
+
+ { // BX_KEY_Q ( ibm 17 ) 
+   { "\x10" , "\x90" },
+   { "\x15" , "\xF0\x15" },
+   { "\x15" , "\xF0\x15" },
+ },
+
+ { // BX_KEY_R ( ibm 20 ) 
+   { "\x13" , "\x93" },
+   { "\x2D" , "\xF0\x2D" },
+   { "\x2D" , "\xF0\x2D" },
+ },
+
+ { // BX_KEY_S ( ibm 32 ) 
+   { "\x1F" , "\x9F" },
+   { "\x1B" , "\xF0\x1B" },
+   { "\x1B" , "\xF0\x1B" },
+ },
+
+ { // BX_KEY_T ( ibm 21 ) 
+   { "\x14" , "\x94" },
+   { "\x2C" , "\xF0\x2C" },
+   { "\x2C" , "\xF0\x2C" },
+ },
+
+ { // BX_KEY_U ( ibm 23 ) 
+   { "\x16" , "\x96" },
+   { "\x3C" , "\xF0\x3C" },
+   { "\x3C" , "\xF0\x3C" },
+ },
+
+ { // BX_KEY_V ( ibm 49 ) 
+   { "\x2F" , "\xAF" },
+   { "\x2A" , "\xF0\x2A" },
+   { "\x2A" , "\xF0\x2A" },
+ },
+
+ { // BX_KEY_W ( ibm 18 ) 
+   { "\x11" , "\x91" },
+   { "\x1D" , "\xF0\x1D" },
+   { "\x1D" , "\xF0\x1D" },
+ },
+
+ { // BX_KEY_X ( ibm 47 ) 
+   { "\x2D" , "\xAD" },
+   { "\x22" , "\xF0\x22" },
+   { "\x22" , "\xF0\x22" },
+ },
+
+ { // BX_KEY_Y ( ibm 22 ) 
+   { "\x15" , "\x95" },
+   { "\x35" , "\xF0\x35" },
+   { "\x35" , "\xF0\x35" },
+ },
+
+ { // BX_KEY_Z ( ibm 46 ) 
+   { "\x2C" , "\xAC" },
+   { "\x1A" , "\xF0\x1A" },
+   { "\x1A" , "\xF0\x1A" },
+ },
+
+ { // BX_KEY_0 ( ibm 11 ) 
+   { "\x0B" , "\x8B" },
+   { "\x45" , "\xF0\x45" },
+   { "\x45" , "\xF0\x45" },
+ },
+
+ { // BX_KEY_1 ( ibm 2 ) 
+   { "\x02" , "\x82" },
+   { "\x16" , "\xF0\x16" },
+   { "\x16" , "\xF0\x16" },
+ },
+
+ { // BX_KEY_2 ( ibm 3 ) 
+   { "\x03" , "\x83" },
+   { "\x1E" , "\xF0\x1E" },
+   { "\x1E" , "\xF0\x1E" },
+ },
+
+ { // BX_KEY_3 ( ibm 4 ) 
+   { "\x04" , "\x84" },
+   { "\x26" , "\xF0\x26" },
+   { "\x26" , "\xF0\x26" },
+ },
+
+ { // BX_KEY_4 ( ibm 5 ) 
+   { "\x05" , "\x85" },
+   { "\x25" , "\xF0\x25" },
+   { "\x25" , "\xF0\x25" },
+ },
+
+ { // BX_KEY_5 ( ibm 6 ) 
+   { "\x06" , "\x86" },
+   { "\x2E" , "\xF0\x2E" },
+   { "\x2E" , "\xF0\x2E" },
+ },
+
+ { // BX_KEY_6 ( ibm 7 ) 
+   { "\x07" , "\x87" },
+   { "\x36" , "\xF0\x36" },
+   { "\x36" , "\xF0\x36" },
+ },
+
+ { // BX_KEY_7 ( ibm 8 ) 
+   { "\x08" , "\x88" },
+   { "\x3D" , "\xF0\x3D" },
+   { "\x3D" , "\xF0\x3D" },
+ },
+
+ { // BX_KEY_8 ( ibm 9 ) 
+   { "\x09" , "\x89" },
+   { "\x3E" , "\xF0\x3E" },
+   { "\x3E" , "\xF0\x3E" },
+ },
+
+ { // BX_KEY_9 ( ibm 10 ) 
+   { "\x0A" , "\x8A" },
+   { "\x46" , "\xF0\x46" },
+   { "\x46" , "\xF0\x46" },
+ },
+
+ { // BX_KEY_ESC ( ibm 110 ) 
+   { "\x01" , "\x81" },
+   { "\x76" , "\xF0\x76" },
+   { "\x08" , "\xF0\x08" },
+ },
+
+ { // BX_KEY_SPACE ( ibm 61 ) 
+   { "\x39" , "\xB9" },
+   { "\x29" , "\xF0\x29" },
+   { "\x29" , "\xF0\x29" },
+ },
+
+ { // BX_KEY_SINGLE_QUOTE ( ibm 41 ) 
+   { "\x28" , "\xA8" },
+   { "\x52" , "\xF0\x52" },
+   { "\x52" , "\xF0\x52" },
+ },
+
+ { // BX_KEY_COMMA ( ibm 53 ) 
+   { "\x33" , "\xB3" },
+   { "\x41" , "\xF0\x41" },
+   { "\x41" , "\xF0\x41" },
+ },
+
+ { // BX_KEY_PERIOD ( ibm 54 ) 
+   { "\x34" , "\xB4" },
+   { "\x49" , "\xF0\x49" },
+   { "\x49" , "\xF0\x49" },
+ },
+
+ { // BX_KEY_SLASH ( ibm 55 ) 
+   { "\x35" , "\xB5" },
+   { "\x4A" , "\xF0\x4A" },
+   { "\x4A" , "\xF0\x4A" },
+ },
+
+ { // BX_KEY_SEMICOLON ( ibm 40 ) 
+   { "\x27" , "\xA7" },
+   { "\x4C" , "\xF0\x4C" },
+   { "\x4C" , "\xF0\x4C" },
+ },
+
+ { // BX_KEY_EQUALS ( ibm 13 ) 
+   { "\x0D" , "\x8D" },
+   { "\x55" , "\xF0\x55" },
+   { "\x55" , "\xF0\x55" },
+ },
+
+ { // BX_KEY_LEFT_BRACKET ( ibm 27 ) 
+   { "\x1A" , "\x9A" },
+   { "\x54" , "\xF0\x54" },
+   { "\x54" , "\xF0\x54" },
+ },
+
+ { // BX_KEY_BACKSLASH ( ibm 42, 29)
+   { "\x2B" , "\xAB" },
+   { "\x5D" , "\xF0\x5D" },
+   { "\x53" , "\xF0\x53" },
+ },
+
+ { // BX_KEY_RIGHT_BRACKET ( ibm 28 ) 
+   { "\x1B" , "\x9B" },
+   { "\x5B" , "\xF0\x5B" },
+   { "\x5B" , "\xF0\x5B" },
+ },
+
+ { // BX_KEY_MINUS ( ibm 12 ) 
+   { "\x0C" , "\x8C" },
+   { "\x4E" , "\xF0\x4E" },
+   { "\x4E" , "\xF0\x4E" },
+ },
+
+ { // BX_KEY_GRAVE ( ibm 1 ) 
+   { "\x29" , "\xA9" },
+   { "\x0E" , "\xF0\x0E" },
+   { "\x0E" , "\xF0\x0E" },
+ },
+
+ { // BX_KEY_BACKSPACE ( ibm 15 ) 
+   { "\x0E" , "\x8E" },
+   { "\x66" , "\xF0\x66" },
+   { "\x66" , "\xF0\x66" },
+ },
+
+ { // BX_KEY_ENTER ( ibm 43 ) 
+   { "\x1C" , "\x9C" },
+   { "\x5A" , "\xF0\x5A" },
+   { "\x5A" , "\xF0\x5A" },
+ },
+
+ { // BX_KEY_TAB ( ibm 16 ) 
+   { "\x0F" , "\x8F" },
+   { "\x0D" , "\xF0\x0D" },
+   { "\x0D" , "\xF0\x0D" },
+ },
+
+ { // BX_KEY_LEFT_BACKSLASH ( ibm 45 ) 
+   { "\x56" , "\xD6" },
+   { "\x61" , "\xF0\x61" },
+   { "\x13" , "\xF0\x13" },
+ },
+
+ { // BX_KEY_PRINT ( ibm 124 ) 
+   { "\xE0\x37" , "\xE0\xB7" },
+   { "\xE0\x7C" , "\xE0\xF0\x7C" },
+   { "\x57" ,     "\xF0\x57" },
+ },
+
+ { // BX_KEY_SCRL_LOCK ( ibm 125 ) 
+   { "\x46" , "\xC6" },
+   { "\x7E" , "\xF0\x7E" },
+   { "\x5F" , "\xF0\x5F" },
+ },
+
+ { // BX_KEY_PAUSE ( ibm 126 ) 
+   { "\xE1\x1D\x45\xE1\x9D\xC5" ,         "" },
+   { "\xE1\x14\x77\xE1\xF0\x14\xF0\x77" , "" },
+   { "\x62" ,                             "\xF0\x62" },
+ },
+
+ { // BX_KEY_INSERT ( ibm 75 ) 
+   { "\xE0\x52" , "\xE0\xD2" },
+   { "\xE0\x70" , "\xE0\xF0\x70" },
+   { "\x67" ,     "\xF0\x67" },
+ },
+
+ { // BX_KEY_DELETE ( ibm 76 ) 
+   { "\xE0\x53" , "\xE0\xD3" },
+   { "\xE0\x71" , "\xE0\xF0\x71" },
+   { "\x64" ,     "\xF0\x64" },
+ },
+
+ { // BX_KEY_HOME ( ibm 80 ) 
+   { "\xE0\x47" , "\xE0\xC7" },
+   { "\xE0\x6C" , "\xE0\xF0\x6C" },
+   { "\x6E" ,     "\xF0\x6E" },
+ },
+
+ { // BX_KEY_END ( ibm 81 ) 
+   { "\xE0\x4F" , "\xE0\xCF" },
+   { "\xE0\x69" , "\xE0\xF0\x69" },
+   { "\x65" ,     "\xF0\x65" },
+ },
+
+ { // BX_KEY_PAGE_UP ( ibm 85 ) 
+   { "\xE0\x49" , "\xE0\xC9" },
+   { "\xE0\x7D" , "\xE0\xF0\x7D" },
+   { "\x6F" ,     "\xF0\x6F" },
+ },
+
+ { // BX_KEY_PAGE_DOWN ( ibm 86 ) 
+   { "\xE0\x51" , "\xE0\xD1" },
+   { "\xE0\x7A" , "\xE0\xF0\x7A" },
+   { "\x6D" ,     "\xF0\x6D" },
+ },
+
+ { // BX_KEY_KP_ADD ( ibm 106 ) 
+   { "\x4E" , "\xCE" },
+   { "\x79" , "\xF0\x79" },
+   { "\x7C" , "\xF0\x7C" },
+ },
+
+ { // BX_KEY_KP_SUBTRACT ( ibm 105 ) 
+   { "\x4A" , "\xCA" },
+   { "\x7B" , "\xF0\x7B" },
+   { "\x84" , "\xF0\x84" },
+ },
+
+ { // BX_KEY_KP_END ( ibm 93 ) 
+   { "\x4F" , "\xCF" },
+   { "\x69" , "\xF0\x69" },
+   { "\x69" , "\xF0\x69" },
+ },
+
+ { // BX_KEY_KP_DOWN ( ibm 98 ) 
+   { "\x50" , "\xD0" },
+   { "\x72" , "\xF0\x72" },
+   { "\x72" , "\xF0\x72" },
+ },
+
+ { // BX_KEY_KP_PAGE_DOWN ( ibm 103 ) 
+   { "\x51" , "\xD1" },
+   { "\x7A" , "\xF0\x7A" },
+   { "\x7A" , "\xF0\x7A" },
+ },
+
+ { // BX_KEY_KP_LEFT ( ibm 92 ) 
+   { "\x4B" , "\xCB" },
+   { "\x6B" , "\xF0\x6B" },
+   { "\x6B" , "\xF0\x6B" },
+ },
+
+ { // BX_KEY_KP_RIGHT ( ibm 102 ) 
+   { "\x4D" , "\xCD" },
+   { "\x74" , "\xF0\x74" },
+   { "\x74" , "\xF0\x74" },
+ },
+
+ { // BX_KEY_KP_HOME ( ibm 91 ) 
+   { "\x47" , "\xC7" },
+   { "\x6C" , "\xF0\x6C" },
+   { "\x6C" , "\xF0\x6C" },
+ },
+
+ { // BX_KEY_KP_UP ( ibm 96 ) 
+   { "\x48" , "\xC8" },
+   { "\x75" , "\xF0\x75" },
+   { "\x75" , "\xF0\x75" },
+ },
+
+ { // BX_KEY_KP_PAGE_UP ( ibm 101 ) 
+   { "\x49" , "\xC9" },
+   { "\x7D" , "\xF0\x7D" },
+   { "\x7D" , "\xF0\x7D" },
+ },
+
+ { // BX_KEY_KP_INSERT ( ibm 99 ) 
+   { "\x52" , "\xD2" },
+   { "\x70" , "\xF0\x70" },
+   { "\x70" , "\xF0\x70" },
+ },
+
+ { // BX_KEY_KP_DELETE ( ibm 104 ) 
+   { "\x53" , "\xD3" },
+   { "\x71" , "\xF0\x71" },
+   { "\x71" , "\xF0\x71" },
+ },
+
+ { // BX_KEY_KP_5 ( ibm 97 ) 
+   { "\x4C" , "\xCC" },
+   { "\x73" , "\xF0\x73" },
+   { "\x73" , "\xF0\x73" },
+ },
+
+ { // BX_KEY_UP ( ibm 83 ) 
+   { "\xE0\x48" , "\xE0\xC8" },
+   { "\xE0\x75" , "\xE0\xF0\x75" },
+   { "\x63" ,     "\xF0\x63" },
+ },
+
+ { // BX_KEY_DOWN ( ibm 84 ) 
+   { "\xE0\x50" , "\xE0\xD0" },
+   { "\xE0\x72" , "\xE0\xF0\x72" },
+   { "\x60" ,     "\xF0\x60" },
+ },
+
+ { // BX_KEY_LEFT ( ibm 79 ) 
+   { "\xE0\x4B" , "\xE0\xCB" },
+   { "\xE0\x6B" , "\xE0\xF0\x6B" },
+   { "\x61" ,     "\xF0\x61" },
+ },
+
+ { // BX_KEY_RIGHT ( ibm 89 ) 
+   { "\xE0\x4D" , "\xE0\xCD" },
+   { "\xE0\x74" , "\xE0\xF0\x74" },
+   { "\x6A" ,     "\xF0\x6A" },
+ },
+
+ { // BX_KEY_KP_ENTER ( ibm 108 ) 
+   { "\xE0\x1C" , "\xE0\x9C" },
+   { "\xE0\x5A" , "\xE0\xF0\x5A" },
+   { "\x79" ,     "\xF0\x79" },
+ },
+
+ { // BX_KEY_KP_MULTIPLY ( ibm 100 ) 
+   { "\x37" , "\xB7" },
+   { "\x7C" , "\xF0\x7C" },
+   { "\x7E" , "\xF0\x7E" },
+ },
+
+ { // BX_KEY_KP_DIVIDE ( ibm 95 ) 
+   { "\xE0\x35" , "\xE0\xB5" },
+   { "\xE0\x4A" , "\xE0\xF0\x4A" },
+   { "\x77" ,     "\xF0\x77" },
+ },
+
+ { // BX_KEY_WIN_L 
+   { "\xE0\x5B" , "\xE0\xDB" },
+   { "\xE0\x1F" , "\xE0\xF0\x1F" },
+   { "\x8B" ,     "\xF0\x8B" },
+ },
+
+ { // BX_KEY_WIN_R
+   { "\xE0\x5C" , "\xE0\xDC" },
+   { "\xE0\x27" , "\xE0\xF0\x27" },
+   { "\x8C" ,     "\xF0\x8C" },
+ },
+
+ { // BX_KEY_MENU
+   { "\xE0\x5D" , "\xE0\xDD" },
+   { "\xE0\x2F" , "\xE0\xF0\x2F" },
+   { "\x8D" ,     "\xF0\x8D" },
+ },
+
+ { // BX_KEY_ALT_SYSREQ
+   { "\x54" ,   "\xD4" },
+   { "\x84" ,   "\xF0\x84" },
+   { "\x57" ,   "\xF0\x57" },
+ },
+
+ { // BX_KEY_CTRL_BREAK
+   { "\xE0\x46" , "\xE0\xC6" },
+   { "\xE0\x7E" , "\xE0\xF0\x7E" },
+   { "\x62" ,     "\xF0\x62" },
+ },
+
+ { // BX_KEY_INT_BACK
+   { "\xE0\x6A" , "\xE0\xEA" },
+   { "\xE0\x38" , "\xE0\xF0\x38" },
+   { "\x38" ,     "\xF0\x38" },
+ },
+
+ { // BX_KEY_INT_FORWARD
+   { "\xE0\x69" , "\xE0\xE9" },
+   { "\xE0\x30" , "\xE0\xF0\x30" },
+   { "\x30" ,     "\xF0\x30" },
+ },
+
+ { // BX_KEY_INT_STOP
+   { "\xE0\x68" , "\xE0\xE8" },
+   { "\xE0\x28" , "\xE0\xF0\x28" },
+   { "\x28" ,     "\xF0\x28" },
+ },
+
+ { // BX_KEY_INT_MAIL
+   { "\xE0\x6C" , "\xE0\xEC" },
+   { "\xE0\x48" , "\xE0\xF0\x48" },
+   { "\x48" ,     "\xF0\x48" },
+ },
+
+ { // BX_KEY_INT_SEARCH
+   { "\xE0\x65" , "\xE0\xE5" },
+   { "\xE0\x10" , "\xE0\xF0\x10" },
+   { "\x10" ,     "\xF0\x10" },
+ },
+
+ { // BX_KEY_INT_FAV
+   { "\xE0\x66" , "\xE0\xE6" },
+   { "\xE0\x18" , "\xE0\xF0\x18" },
+   { "\x18" ,     "\xF0\x18" },
+ },
+
+ { // BX_KEY_INT_HOME
+   { "\xE0\x32" , "\xE0\xB2" },
+   { "\xE0\x3A" , "\xE0\xF0\x3A" },
+   { "\x97" ,     "\xF0\x97" },
+ },
+
+ { // BX_KEY_POWER_MYCOMP
+   { "\xE0\x6B" , "\xE0\xEB" },
+   { "\xE0\x40" , "\xE0\xF0\x40" },
+   { "\x40" ,     "\xF0\x40" },
+ },
+
+ { // BX_KEY_POWER_CALC
+   { "\xE0\x21" , "\xE0\xA1" },
+   { "\xE0\x2B" , "\xE0\xF0\x2B" },
+   { "\x99" ,     "\xF0\x99" },
+ },
+
+ { // BX_KEY_POWER_SLEEP
+   { "\xE0\x5F" , "\xE0\xDF" },
+   { "\xE0\x3F" , "\xE0\xF0\x3F" },
+   { "\x7F" ,     "\xF0\x7F" },
+ },
+
+ { // BX_KEY_POWER_POWER
+   { "\xE0\x5E" , "\xE0\xDE" },
+   { "\xE0\x37" , "\xE0\xF0\x37" },
+   { "" ,         "" },
+ },
+
+ { // BX_KEY_POWER_WAKE
+   { "\xE0\x63" , "\xE0\xE3" },
+   { "\xE0\x5E" , "\xE0\xF0\x5E" },
+   { "" ,         "" },
+ },
+
+};
diff --git a/tools/ioemu/iodev/scancodes.h b/tools/ioemu/iodev/scancodes.h
new file mode 100644 (file)
index 0000000..f26491b
--- /dev/null
@@ -0,0 +1,31 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scancodes.h,v 1.4 2002/10/24 21:07:51 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Translation table of the 8042
+extern unsigned char translation8042[256];
+
+typedef struct { 
+  const char *make;
+  const char *brek;
+  }scancode;
+
+// Scancodes table
+extern scancode scancodes[BX_KEY_NBKEYS][3];
diff --git a/tools/ioemu/iodev/scsi_commands.h b/tools/ioemu/iodev/scsi_commands.h
new file mode 100644 (file)
index 0000000..c516fde
--- /dev/null
@@ -0,0 +1,418 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsi_commands.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+/* scsi/commands.h
+   Used only in cdrom_amigaos.cc.
+
+       Operation codes for SCSI-2 commands
+
+   30 Nov 94   Peter Urbanec    Created file
+   10 Jan 95   Peter Urbanec    Added SCSI_ prefix to all commands
+   31 Jan 95   Peter Urbanec    Released to public
+
+*/
+
+
+/* All device types */
+
+#define SCSI_CHANGE_DEFINITION                 0x40
+#define SCSI_COMPARE                           0x39
+#define SCSI_COPY                              0x18
+#define SCSI_COPY_AND_VERIFY                   0x3a
+#define SCSI_INQUIRY                           0x12
+#define SCSI_LOG_SELECT                                0x4c
+#define SCSI_LOG_SENSE                         0x4d
+#define SCSI_MODE_SELECT_6                     0x15
+#define SCSI_MODE_SELECT_10                    0x55
+#define SCSI_MODE_SENSE_6                      0x1a
+#define SCSI_MODE_SENSE_10                     0x5a
+#define SCSI_READ_BUFFER                       0x3c
+#define SCSI_RECEIVE_DIAGNOSTIC_RESULTS                0x1c
+#define SCSI_REQUEST_SENSE                     0x03
+#define SCSI_SEND_DIAGNOSTIC                   0x1d
+#define SCSI_TEST_UNIT_READY                   0x00
+#define SCSI_WRITE_BUFFER                      0x3b
+
+
+/* Direct Access devices */
+
+#define SCSI_DA_CHANGE_DEFINITION              0x40
+#define SCSI_DA_COMPARE                                0x39
+#define SCSI_DA_COPY                           0x18
+#define SCSI_DA_COPY_AND_VERIFY                        0x3a
+#define SCSI_DA_FORMAT_UNIT                    0x04
+#define SCSI_DA_INQUIRY                                0x12
+#define SCSI_DA_LOCK_UNLOCK_CACHE              0x36
+#define SCSI_DA_LOG_SELECT                     0x4c
+#define SCSI_DA_LOG_SENSE                      0x4d
+#define SCSI_DA_MODE_SELECT_6                  0x15
+#define SCSI_DA_MODE_SELECT_10                 0x55
+#define SCSI_DA_MODE_SENSE_6                   0x1a
+#define SCSI_DA_MODE_SENSE_10                  0x5a
+#define SCSI_DA_PRE_FETCH                      0x34
+#define SCSI_DA_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_DA_READ_6                         0x08
+#define SCSI_DA_READ_10                                0x28
+#define SCSI_DA_READ_BUFFER                    0x3c
+#define SCSI_DA_READ_CAPACITY                  0x25
+#define SCSI_DA_READ_DEFECT_DATA               0x37
+#define SCSI_DA_READ_LONG                      0x3e
+#define SCSI_DA_REASSIGN_BLOCKS                        0x07
+#define SCSI_DA_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_DA_RELEASE                                0x17
+#define SCSI_DA_REQUEST_SENSE                  0x03
+#define SCSI_DA_RESERVE                                0x16
+#define SCSI_DA_REZERO_UNIT                    0x01
+#define SCSI_DA_SEARCH_DATA_EQUAL              0x31
+#define SCSI_DA_SEARCH_DATA_HIGH               0x30
+#define SCSI_DA_SEARCH_DATA_LOW                        0x32
+#define SCSI_DA_SEEK_6                         0x0b
+#define SCSI_DA_SEEK_10                                0x2b
+#define SCSI_DA_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_DA_SET_LIMITS                     0x33
+#define SCSI_DA_START_STOP_UNIT                        0x1b
+#define SCSI_DA_SYNCHRONIZE_CACHE              0x35
+#define SCSI_DA_TEST_UNIT_READY                        0x00
+#define SCSI_DA_VERIFY                         0x2f
+
+
+/* Sequential access devices */
+
+#define SCSI_SA_CHANGE_DEFINITION              0x40
+#define SCSI_SA_COMPARE                                0x39
+#define SCSI_SA_COPY                           0x18
+#define SCSI_SA_COPY_AND_VERIFY                        0x3a
+#define SCSI_SA_ERASE                          0x19
+#define SCSI_SA_INQUIRY                                0x12
+#define SCSI_SA_LOAD_UNLOAD                    0x1b
+#define SCSI_SA_LOCATE                         0x2b
+#define SCSI_SA_LOG_SELECT                     0x4c
+#define SCSI_SA_LOG_SENSE                      0x4d
+#define SCSI_SA_MODE_SELECT_6                  0x15
+#define SCSI_SA_MODE_SELECT_10                 0x55
+#define SCSI_SA_MODE_SENSE_6                   0x1a
+#define SCSI_SA_MODE_SENSE_10                  0x5a
+#define SCSI_SA_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_SA_READ                           0x08
+#define SCSI_SA_READ_BLOCK_LIMITS              0x05
+#define SCSI_SA_READ_BUFFER                    0x3c
+#define SCSI_SA_READ_POSITION                  0x34
+#define SCSI_SA_READ_REVERSE                   0x0f
+#define SCSI_SA_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_SA_RECOVER_BUFFERED_DATA          0x14
+#define SCSI_SA_RELEASE_UNIT                   0x17
+#define SCSI_SA_REQUEST_SENSE                  0x03
+#define SCSI_SA_RESERVE_UNIT                   0x16
+#define SCSI_SA_REWIND                         0x01
+#define SCSI_SA_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_SA_SPACE                          0x11
+#define SCSI_SA_TEST_UNIT_READY                        0x00
+#define SCSI_SA_VERIFY                         0x13
+#define SCSI_SA_WRITE                          0x0a
+#define SCSI_SA_WRITE_BUFFER                   0x3b
+#define SCSI_SA_WRITE_FILEMARKS                        0x10
+
+
+/* Printer devices */
+
+#define SCSI_PRT_CHANGE_DEFINITION             0x40
+#define SCSI_PRT_COMPARE                       0x39
+#define SCSI_PRT_COPY                          0x18
+#define SCSI_PRT_COPY_AND_VERIFY               0x3a
+#define SCSI_PRT_FORMAT                                0x04
+#define SCSI_PRT_INQUIRY                       0x12
+#define SCSI_PRT_LOG_SELECT                    0x4c
+#define SCSI_PRT_LOG_SENSE                     0x4d
+#define SCSI_PRT_MODE_SELECT_6                 0x15
+#define SCSI_PRT_MODE_SELECT_10                        0x55
+#define SCSI_PRT_MODE_SENSE_6                  0x1a
+#define SCSI_PRT_MODE_SENSE_10                 0x5a
+#define SCSI_PRT_PRINT                         0x0a
+#define SCSI_PRT_READ_BUFFER                   0x3c
+#define SCSI_PRT_RECEIVE_DIAGNOSTIC_RESULTS    0x1c
+#define SCSI_PRT_RECOVER_BUFFERED_DATA         0x14
+#define SCSI_PRT_RELEASE_UNIT                  0x17
+#define SCSI_PRT_REQUEST_SENSE                 0x03
+#define SCSI_PRT_RESERVE_UNIT                  0x16
+#define SCSI_PRT_SEND_DIAGNOSTIC               0x1d
+#define SCSI_PRT_SLEW_AND_PRINT                        0x0b
+#define SCSI_PRT_STOP_PRINT                    0x1b
+#define SCSI_PRT_SYNCHRONIZE_BUFFER            0x10
+#define SCSI_PRT_TEST_UNIT_READY               0x00
+#define SCSI_PRT_WRITE_BUFFER                  0x3b
+
+
+/* Processor devices */
+
+#define SCSI_CPU_CHANGE_DEFINITION             0x40
+#define SCSI_CPU_COMPARE                       0x39
+#define SCSI_CPU_COPY                          0x18
+#define SCSI_CPU_COPY_AND_VERIFY               0x3a
+#define SCSI_CPU_INQUIRY                       0x12
+#define SCSI_CPU_LOG_SELECT                    0x4c
+#define SCSI_CPU_LOG_SENSE                     0x4d
+#define SCSI_CPU_READ_BUFFER                   0x3c
+#define SCSI_CPU_RECEIVE                       0x08
+#define SCSI_CPU_RECEIVE_DIAGNOSTIC_RESULTS    0x1c
+#define SCSI_CPU_REQUEST_SENSE                 0x03
+#define SCSI_CPU_SEND                          0x0a
+#define SCSI_CPU_SEND_DIAGNOSTIC               0x1d
+#define SCSI_CPU_TEST_UNIT_READY               0x00
+#define SCSI_CPU_WRITE_BUFFER                  0x3b
+
+
+/* Write Once devices */
+
+#define SCSI_WO_CHANGE_DEFINITION              0x40
+#define SCSI_WO_COMPARE                                0x39
+#define SCSI_WO_COPY                           0x18
+#define SCSI_WO_COPY_AND_VERIFY                        0x3a
+#define SCSI_WO_INQUIRY                                0x12
+#define SCSI_WO_LOCK_UNLOCK_CACHE              0x36
+#define SCSI_WO_LOG_SELECT                     0x4c
+#define SCSI_WO_LOG_SENSE                      0x4d
+#define SCSI_WO_MEDIUM_SCAN                    0x38
+#define SCSI_WO_MODE_SELECT_6                  0x15
+#define SCSI_WO_MODE_SELECT_10                 0x55
+#define SCSI_WO_MODE_SENSE_6                   0x1a
+#define SCSI_WO_MODE_SENSE_10                  0x5a
+#define SCSI_WO_PRE_FETCH                      0x34
+#define SCSI_WO_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_WO_READ_6                         0x08
+#define SCSI_WO_READ_10                                0x28
+#define SCSI_WO_READ_12                                0xa8
+#define SCSI_WO_READ_BUFFER                    0x3c
+#define SCSI_WO_READ_CAPACITY                  0x25
+#define SCSI_WO_READ_LONG                      0x3e
+#define SCSI_WO_REASSIGN_BLOCKS                        0x07
+#define SCSI_WO_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_WO_RELEASE                                0x17
+#define SCSI_WO_REQUEST_SENSE                  0x03
+#define SCSI_WO_RESERVE                                0x16
+#define SCSI_WO_REZERO_UNIT                    0x01
+#define SCSI_WO_SEARCH_DATA_EQUAL_10           0x31
+#define SCSI_WO_SEARCH_DATA_EQUAL_12           0xb1
+#define SCSI_WO_SEARCH_DATA_HIGH_10            0x30
+#define SCSI_WO_SEARCH_DATA_HIGH_12            0xb0
+#define SCSI_WO_SEARCH_DATA_LOW_10             0x32
+#define SCSI_WO_SEARCH_DATA_LOW_12             0xb2
+#define SCSI_WO_SEEK_6                         0x0b
+#define SCSI_WO_SEEK_10                                0x2b
+#define SCSI_WO_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_WO_SET_LIMITS_10                  0x33
+#define SCSI_WO_SET_LIMITS_12                  0xb3
+#define SCSI_WO_START_STOP_UNIT                        0x1b
+#define SCSI_WO_SYNCHRONIZE_CACHE              0x35
+#define SCSI_WO_TEST_UNIT_READY                        0x00
+#define SCSI_WO_VERIFY_10                      0x2f
+#define SCSI_WO_VERIFY_12                      0xaf
+#define SCSI_WO_WRITE_6                                0x0a
+#define SCSI_WO_WRITE_10                       0x2a
+#define SCSI_WO_WRITE_12                       0xaa
+#define SCSI_WO_WRITE_AND_VERIFY_10            0x2e
+#define SCSI_WO_WRITE_AND_VERIFY_12            0xae
+#define SCSI_WO_WRITE_BUFFER                   0x3b
+#define SCSI_WO_WRITE_LONG                     0x3f
+
+
+/* CD-ROM devices */
+
+#define SCSI_CD_CHANGE_DEFINITION              0x40
+#define SCSI_CD_COMPARE                                0x39
+#define SCSI_CD_COPY                           0x18
+#define SCSI_CD_COPY_AND_VERIFY                        0x3a
+#define SCSI_CD_INQUIRY                                0x12
+#define SCSI_CD_LOCK_UNLOCK_CACHE              0x36
+#define SCSI_CD_LOG_SELECT                     0x4c
+#define SCSI_CD_LOG_SENSE                      0x4d
+#define SCSI_CD_MODE_SELECT_6                  0x15
+#define SCSI_CD_MODE_SELECT_10                 0x55
+#define SCSI_CD_MODE_SENSE_6                   0x1a
+#define SCSI_CD_MODE_SENSE_10                  0x5a
+#define SCSI_CD_PAUSE_RESUME                   0x4b
+#define SCSI_CD_PLAY_AUDIO_10                  0x45
+#define SCSI_CD_PLAY_AUDIO_12                  0xa5
+#define SCSI_CD_PLAY_AUDIO_MSF                 0x47
+#define SCSI_CD_PLAY_AUDIO_TRACK_INDEX         0x48
+#define SCSI_CD_PLAY_TRACK_RELATIVE_10         0x49
+#define SCSI_CD_PLAY_TRACK_RELATIVE_12         0xa9
+#define SCSI_CD_PRE_FETCH                      0x34
+#define SCSI_CD_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_CD_READ_6                         0x08
+#define SCSI_CD_READ_10                                0x28
+#define SCSI_CD_READ_12                                0xa8
+#define SCSI_CD_READ_BUFFER                    0x3c
+#define SCSI_CD_READ_CD_ROM_CAPACITY           0x25
+#define SCSI_CD_READ_HEADER                    0x44
+#define SCSI_CD_READ_LONG                      0x3e
+#define SCSI_CD_READ_SUB_CHANNEL               0x42
+#define SCSI_CD_READ_TOC                       0x43
+#define SCSI_CD_RECEIVE_DIAGNOSTIC_RESULT      0x1c
+#define SCSI_CD_RELEASE                                0x17
+#define SCSI_CD_REQUEST_SENSE                  0x03
+#define SCSI_CD_RESERVE                                0x16
+#define SCSI_CD_REZERO_UNIT                    0x01
+#define SCSI_CD_SEARCH_DATA_EQUAL_10           0x31
+#define SCSI_CD_SEARCH_DATA_EQUAL_12           0xb1
+#define SCSI_CD_SEARCH_DATA_HIGH_10            0x30
+#define SCSI_CD_SEARCH_DATA_HIGH_12            0xb0
+#define SCSI_CD_SEARCH_DATA_LOW_10             0x32
+#define SCSI_CD_SEARCH_DATA_LOW_12             0xb2
+#define SCSI_CD_SEEK_6                         0x0b
+#define SCSI_CD_SEEK_10                                0x2b
+#define SCSI_CD_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_CD_SET_LIMITS_10                  0x33
+#define SCSI_CD_SET_LIMITS_12                  0xb3
+#define SCSI_CD_START_STOP_UNIT                        0x1b
+#define SCSI_CD_SYNCHRONIZE_CACHE              0x35
+#define SCSI_CD_TEST_UNIT_READY                        0x00
+#define SCSI_CD_VERIFY_10                      0x2f
+#define SCSI_CD_VERIFY_12                      0xaf
+#define SCSI_CD_WRITE_BUFFER                   0x3b
+
+
+/* Scanner devices */
+
+#define SCSI_SC_CHANGE_DEFINITION              0x40
+#define SCSI_SC_COMPARE                                0x39
+#define SCSI_SC_COPY                           0x18
+#define SCSI_SC_COPY_AND_VERIFY                        0x3a
+#define SCSI_SC_GET_DATA_BUFFER_STATUS         0x34
+#define SCSI_SC_GET_WINDOW                     0x25
+#define SCSI_SC_INQUIRY                                0x12
+#define SCSI_SC_LOG_SELECT                     0x4c
+#define SCSI_SC_LOG_SENSE                      0x4d
+#define SCSI_SC_MODE_SELECT_6                  0x15
+#define SCSI_SC_MODE_SELECT_10                 0x55
+#define SCSI_SC_MODE_SENSE_6                   0x1a
+#define SCSI_SC_MODE_SENSE_10                  0x5a
+#define SCSI_SC_OBJECT_POSITION                        0x31
+#define SCSI_SC_READ                           0x28
+#define SCSI_SC_READ_BUFFER                    0x3c
+#define SCSI_SC_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_SC_RELEASE_UNIT                   0x17
+#define SCSI_SC_REQUEST_SENSE                  0x03
+#define SCSI_SC_RESERVE_UNIT                   0x16
+#define SCSI_SC_SCAN                           0x1b
+#define SCSI_SC_SET_WINDOW                     0x24
+#define SCSI_SC_SEND                           0x2a
+#define SCSI_SC_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_SC_TEST_UNIT_READY                        0x00
+#define SCSI_SC_WRITE_BUFFER                   0x3b
+
+
+/* Optical memory devices */
+
+#define SCSI_OM_CHANGE_DEFINITION              0x40
+#define SCSI_OM_COMPARE                                0x39
+#define SCSI_OM_COPY                           0x18
+#define SCSI_OM_COPY_AND_VERIFY                        0x3a
+#define SCSI_OM_ERASE_10                       0x2c
+#define SCSI_OM_ERASE_12                       0xac
+#define SCSI_OM_FORMAT_UNIT                    0x04
+#define SCSI_OM_INQUIRY                                0x12
+#define SCSI_OM_LOCK_UNLOCK_CACHE              0x36
+#define SCSI_OM_LOG_SELECT                     0x4c
+#define SCSI_OM_LOG_SENSE                      0x4d
+#define SCSI_OM_MEDIUM_SCAN                    0x38
+#define SCSI_OM_MODE_SELECT_6                  0x15
+#define SCSI_OM_MODE_SELECT_10                 0x55
+#define SCSI_OM_MODE_SENSE_6                   0x1a
+#define SCSI_OM_MODE_SENSE_10                  0x5a
+#define SCSI_OM_PRE_FETCH                      0x34
+#define SCSI_OM_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_OM_READ_6                         0x08
+#define SCSI_OM_READ_10                                0x28
+#define SCSI_OM_READ_12                                0xa8
+#define SCSI_OM_READ_BUFFER                    0x3c
+#define SCSI_OM_READ_CAPACITY                  0x25
+#define SCSI_OM_READ_DEFECT_DATA_10            0x37
+#define SCSI_OM_READ_DEFECT_DATA_12            0xb7
+#define SCSI_OM_READ_GENERATION                        0x29
+#define SCSI_OM_READ_LONG                      0x3e
+#define SCSI_OM_READ_UPDATED_BLOCK             0x2d
+#define SCSI_OM_REASSIGN_BLOCKS                        0x07
+#define SCSI_OM_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_OM_RELEASE                                0x17
+#define SCSI_OM_REQUEST_SENSE                  0x03
+#define SCSI_OM_RESERVE                                0x16
+#define SCSI_OM_REZERO_UNIT                    0x01
+#define SCSI_OM_SEARCH_DATA_EQUAL_10           0x31
+#define SCSI_OM_SEARCH_DATA_EQUAL_12           0xb1
+#define SCSI_OM_SEARCH_DATA_HIGH_10            0x30
+#define SCSI_OM_SEARCH_DATA_HIGH_12            0xb0
+#define SCSI_OM_SEARCH_DATA_LOW_10             0x32
+#define SCSI_OM_SEARCH_DATA_LOW_12             0xb2
+#define SCSI_OM_SEEK_6                         0x0b
+#define SCSI_OM_SEEK_10                                0x2b
+#define SCSI_OM_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_OM_SET_LIMITS_10                  0x33
+#define SCSI_OM_SET_LIMITS_12                  0xb3
+#define SCSI_OM_START_STOP_UNIT                        0x1b
+#define SCSI_OM_SYNCHRONIZE_CACHE              0x35
+#define SCSI_OM_TEST_UNIT_READY                        0x00
+#define SCSI_OM_UPDATE_BLOCK                   0x3d
+#define SCSI_OM_VERIFY_10                      0x2f
+#define SCSI_OM_VERIFY_12                      0xaf
+#define SCSI_OM_WRITE_6                                0x0a
+#define SCSI_OM_WRITE_10                       0x2a
+#define SCSI_OM_WRITE_12                       0xaa
+#define SCSI_OM_WRITE_AND_VERIFY_10            0x2e
+#define SCSI_OM_WRITE_AND_VERIFY_12            0xae
+#define SCSI_OM_WRITE_BUFFER                   0x3b
+#define SCSI_OM_WRITE_LONG                     0x3f
+
+
+/* Medium changer devices */
+
+#define SCSI_MC_CHANGE_DEFINITION              0x40
+#define SCSI_MC_EXCHANGE_MEDIUM                        0xa6
+#define SCSI_MC_INITIALIZE_ELEMENT_STATUS      0x07
+#define SCSI_MC_INQUIRY                                0x12
+#define SCSI_MC_LOG_SELECT                     0x4c
+#define SCSI_MC_LOG_SENSE                      0x4d
+#define SCSI_MC_MODE_SELECT_6                  0x15
+#define SCSI_MC_MODE_SELECT_10                 0x55
+#define SCSI_MC_MODE_SENSE_6                   0x1a
+#define SCSI_MC_MODE_SENSE_10                  0x5a
+#define SCSI_MC_MOVE_MEDIUM                    0xa5
+#define SCSI_MC_POSITION_TO_ELEMENT            0x2b
+#define SCSI_MC_PREVENT_ALLOW_MEDIUM_REMOVAL   0x1e
+#define SCSI_MC_READ_BUFFER                    0x3c
+#define SCSI_MC_READ_ELEMENT_STATUS            0xb8
+#define SCSI_MC_RECEIVE_DIAGNOSTIC_RESULTS     0x1c
+#define SCSI_MC_RELEASE                                0x17
+#define SCSI_MC_REQUEST_VOLUME_ELEMENT_ADDRESS 0xb5
+#define SCSI_MC_REQUEST_SENSE                  0x03
+#define SCSI_MC_RESERVE                                0x16
+#define SCSI_MC_REZERO_UNIT                    0x01
+#define SCSI_MC_SEND_DIAGNOSTIC                        0x1d
+#define SCSI_MC_SEND_VOLUME_TAG                        0xb6
+#define SCSI_MC_TEST_UNIT_READY                        0x00
+#define SCSI_MC_WRITE_BUFFER                   0x3b
+
+
+/* Communications devices */
+
+#define SCSI_COM_CHANGE_DEFINITION             0x40
+#define SCSI_COM_GET_MESSAGE_6                 0x08
+#define SCSI_COM_GET_MESSAGE_10                        0x28
+#define SCSI_COM_GET_MESSAGE_12                        0xa8
+#define SCSI_COM_INQUIRY                       0x12
+#define SCSI_COM_LOG_SELECT                    0x4c
+#define SCSI_COM_LOG_SENSE                     0x4d
+#define SCSI_COM_MODE_SELECT_6                 0x15
+#define SCSI_COM_MODE_SELECT_10                        0x55
+#define SCSI_COM_MODE_SENSE_6                  0x1a
+#define SCSI_COM_MODE_SENSE_10                 0x5a
+#define SCSI_COM_READ_BUFFER                   0x3c
+#define SCSI_COM_RECEIVE_DIAGNOSTIC_RESULTS    0x1c
+#define SCSI_COM_REQUEST_SENSE                 0x03
+#define SCSI_COM_SEND_DIAGNOSTIC               0x1d
+#define SCSI_COM_SEND_MESSAGE_6                        0x0a
+#define SCSI_COM_SEND_MESSAGE_10               0x2a
+#define SCSI_COM_SEND_MESSAGE_12               0xaa
+#define SCSI_COM_TEST_UNIT_READY               0x00
+#define SCSI_COM_WRITE_BUFFER                  0x3b
+
diff --git a/tools/ioemu/iodev/scsidefs.h b/tools/ioemu/iodev/scsidefs.h
new file mode 100644 (file)
index 0000000..86239e8
--- /dev/null
@@ -0,0 +1,286 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsidefs.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// iodev/scsidefs.h
+// $Id: scsidefs.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+//
+// This file was copied from ... ?
+//
+
+//***************************************************************************
+//
+// Name:            SCSIDEFS.H
+//
+// Description: SCSI definitions ('C' Language)
+//
+//***************************************************************************
+
+//***************************************************************************
+//                          %%% TARGET STATUS VALUES %%%
+//***************************************************************************
+#define STATUS_GOOD     0x00    // Status Good
+#define STATUS_CHKCOND  0x02    // Check Condition
+#define STATUS_CONDMET  0x04    // Condition Met
+#define STATUS_BUSY     0x08    // Busy
+#define STATUS_INTERM   0x10    // Intermediate
+#define STATUS_INTCDMET 0x14    // Intermediate-condition met
+#define STATUS_RESCONF  0x18    // Reservation conflict
+#define STATUS_COMTERM  0x22    // Command Terminated
+#define STATUS_QFULL    0x28    // Queue full
+
+//***************************************************************************
+//                      %%% SCSI MISCELLANEOUS EQUATES %%%
+//***************************************************************************
+#define MAXLUN          7       // Maximum Logical Unit Id
+#define MAXTARG         7       // Maximum Target Id
+#define MAX_SCSI_LUNS   64      // Maximum Number of SCSI LUNs
+#define MAX_NUM_HA      8       // Maximum Number of SCSI HA's
+
+//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+//
+//                          %%% SCSI COMMAND OPCODES %%%
+//
+///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+
+//***************************************************************************
+//               %%% Commands for all Device Types %%%
+//***************************************************************************
+#define SCSI_CHANGE_DEF 0x40    // Change Definition (Optional)
+#define SCSI_COMPARE    0x39    // Compare (O)
+#define SCSI_COPY       0x18    // Copy (O)
+#define SCSI_COP_VERIFY 0x3A    // Copy and Verify (O)
+#define SCSI_INQUIRY    0x12    // Inquiry (MANDATORY)
+#define SCSI_LOG_SELECT 0x4C    // Log Select (O)
+#define SCSI_LOG_SENSE  0x4D    // Log Sense (O)
+#define SCSI_MODE_SEL6  0x15    // Mode Select 6-byte (Device Specific)
+#define SCSI_MODE_SEL10 0x55    // Mode Select 10-byte (Device Specific)
+#define SCSI_MODE_SEN6  0x1A    // Mode Sense 6-byte (Device Specific)
+#define SCSI_MODE_SEN10 0x5A    // Mode Sense 10-byte (Device Specific)
+#define SCSI_READ_BUFF  0x3C    // Read Buffer (O)
+#define SCSI_REQ_SENSE  0x03    // Request Sense (MANDATORY)
+#define SCSI_SEND_DIAG  0x1D    // Send Diagnostic (O)
+#define SCSI_TST_U_RDY  0x00    // Test Unit Ready (MANDATORY)
+#define SCSI_WRITE_BUFF 0x3B    // Write Buffer (O)
+
+//***************************************************************************
+//            %%% Commands Unique to Direct Access Devices %%%
+//***************************************************************************
+#define SCSI_COMPARE    0x39    // Compare (O)
+#define SCSI_FORMAT     0x04    // Format Unit (MANDATORY)
+#define SCSI_LCK_UN_CAC 0x36    // Lock Unlock Cache (O)
+#define SCSI_PREFETCH   0x34    // Prefetch (O)
+#define SCSI_MED_REMOVL 0x1E    // Prevent/Allow medium Removal (O)
+#define SCSI_READ6      0x08    // Read 6-byte (MANDATORY)
+#define SCSI_READ10     0x28    // Read 10-byte (MANDATORY)
+#define SCSI_RD_CAPAC   0x25    // Read Capacity (MANDATORY)
+#define SCSI_RD_DEFECT  0x37    // Read Defect Data (O)
+#define SCSI_READ_LONG  0x3E    // Read Long (O)
+#define SCSI_REASS_BLK  0x07    // Reassign Blocks (O)
+#define SCSI_RCV_DIAG   0x1C    // Receive Diagnostic Results (O)
+#define SCSI_RELEASE    0x17    // Release Unit (MANDATORY)
+#define SCSI_REZERO     0x01    // Rezero Unit (O)
+#define SCSI_SRCH_DAT_E 0x31    // Search Data Equal (O)
+#define SCSI_SRCH_DAT_H 0x30    // Search Data High (O)
+#define SCSI_SRCH_DAT_L 0x32    // Search Data Low (O)
+#define SCSI_SEEK6      0x0B    // Seek 6-Byte (O)
+#define SCSI_SEEK10     0x2B    // Seek 10-Byte (O)
+#define SCSI_SEND_DIAG  0x1D    // Send Diagnostics (MANDATORY)
+#define SCSI_SET_LIMIT  0x33    // Set Limits (O)
+#define SCSI_START_STP  0x1B    // Start/Stop Unit (O)
+#define SCSI_SYNC_CACHE 0x35    // Synchronize Cache (O)
+#define SCSI_VERIFY     0x2F    // Verify (O)
+#define SCSI_WRITE6     0x0A    // Write 6-Byte (MANDATORY)
+#define SCSI_WRITE10    0x2A    // Write 10-Byte (MANDATORY)
+#define SCSI_WRT_VERIFY 0x2E    // Write and Verify (O)
+#define SCSI_WRITE_LONG 0x3F    // Write Long (O)
+#define SCSI_WRITE_SAME 0x41    // Write Same (O)
+
+//***************************************************************************
+//          %%% Commands Unique to Sequential Access Devices %%%
+//***************************************************************************
+#define SCSI_ERASE      0x19    // Erase (MANDATORY)
+#define SCSI_LOAD_UN    0x1B    // Load/Unload (O)
+#define SCSI_LOCATE     0x2B    // Locate (O)
+#define SCSI_RD_BLK_LIM 0x05    // Read Block Limits (MANDATORY)
+#define SCSI_READ_POS   0x34    // Read Position (O)
+#define SCSI_READ_REV   0x0F    // Read Reverse (O)
+#define SCSI_REC_BF_DAT 0x14    // Recover Buffer Data (O)
+#define SCSI_RESERVE    0x16    // Reserve Unit (MANDATORY)
+#define SCSI_REWIND     0x01    // Rewind (MANDATORY)
+#define SCSI_SPACE      0x11    // Space (MANDATORY)
+#define SCSI_VERIFY_T   0x13    // Verify (Tape) (O)
+#define SCSI_WRT_FILE   0x10    // Write Filemarks (MANDATORY)
+
+//***************************************************************************
+//                %%% Commands Unique to Printer Devices %%%
+//***************************************************************************
+#define SCSI_PRINT      0x0A    // Print (MANDATORY)
+#define SCSI_SLEW_PNT   0x0B    // Slew and Print (O)
+#define SCSI_STOP_PNT   0x1B    // Stop Print (O)
+#define SCSI_SYNC_BUFF  0x10    // Synchronize Buffer (O)
+
+//***************************************************************************
+//               %%% Commands Unique to Processor Devices %%%
+//***************************************************************************
+#define SCSI_RECEIVE    0x08        // Receive (O)
+#define SCSI_SEND       0x0A        // Send (O)
+
+//***************************************************************************
+//              %%% Commands Unique to Write-Once Devices %%%
+//***************************************************************************
+#define SCSI_MEDIUM_SCN 0x38    // Medium Scan (O)
+#define SCSI_SRCHDATE10 0x31    // Search Data Equal 10-Byte (O)
+#define SCSI_SRCHDATE12 0xB1    // Search Data Equal 12-Byte (O)
+#define SCSI_SRCHDATH10 0x30    // Search Data High 10-Byte (O)
+#define SCSI_SRCHDATH12 0xB0    // Search Data High 12-Byte (O)
+#define SCSI_SRCHDATL10 0x32    // Search Data Low 10-Byte (O)
+#define SCSI_SRCHDATL12 0xB2    // Search Data Low 12-Byte (O)
+#define SCSI_SET_LIM_10 0x33    // Set Limits 10-Byte (O)
+#define SCSI_SET_LIM_12 0xB3    // Set Limits 10-Byte (O)
+#define SCSI_VERIFY10   0x2F    // Verify 10-Byte (O)
+#define SCSI_VERIFY12   0xAF    // Verify 12-Byte (O)
+#define SCSI_WRITE12    0xAA    // Write 12-Byte (O)
+#define SCSI_WRT_VER10  0x2E    // Write and Verify 10-Byte (O)
+#define SCSI_WRT_VER12  0xAE    // Write and Verify 12-Byte (O)
+
+//***************************************************************************
+//                %%% Commands Unique to CD-ROM Devices %%%
+//***************************************************************************
+#define SCSI_PLAYAUD_10 0x45    // Play Audio 10-Byte (O)
+#define SCSI_PLAYAUD_12 0xA5    // Play Audio 12-Byte 12-Byte (O)
+#define SCSI_PLAYAUDMSF 0x47    // Play Audio MSF (O)
+#define SCSI_PLAYA_TKIN 0x48    // Play Audio Track/Index (O)
+#define SCSI_PLYTKREL10 0x49    // Play Track Relative 10-Byte (O)
+#define SCSI_PLYTKREL12 0xA9    // Play Track Relative 12-Byte (O)
+#define SCSI_READCDCAP  0x25    // Read CD-ROM Capacity (MANDATORY)
+#define SCSI_READHEADER 0x44    // Read Header (O)
+#define SCSI_SUBCHANNEL 0x42    // Read Subchannel (O)
+#define SCSI_READ_TOC   0x43    // Read TOC (O)
+
+//***************************************************************************
+//                %%% Commands Unique to Scanner Devices %%%
+//***************************************************************************
+#define SCSI_GETDBSTAT  0x34    // Get Data Buffer Status (O)
+#define SCSI_GETWINDOW  0x25    // Get Window (O)
+#define SCSI_OBJECTPOS  0x31    // Object Postion (O)
+#define SCSI_SCAN       0x1B    // Scan (O)
+#define SCSI_SETWINDOW  0x24    // Set Window (MANDATORY)
+
+//***************************************************************************
+//           %%% Commands Unique to Optical Memory Devices %%%
+//***************************************************************************
+#define SCSI_UpdateBlk  0x3D    // Update Block (O)
+
+//***************************************************************************
+//           %%% Commands Unique to Medium Changer Devices %%%
+//***************************************************************************
+#define SCSI_EXCHMEDIUM 0xA6    // Exchange Medium (O)
+#define SCSI_INITELSTAT 0x07    // Initialize Element Status (O)
+#define SCSI_POSTOELEM  0x2B    // Position to Element (O)
+#define SCSI_REQ_VE_ADD 0xB5    // Request Volume Element Address (O)
+#define SCSI_SENDVOLTAG 0xB6    // Send Volume Tag (O)
+
+//***************************************************************************
+//            %%% Commands Unique to Communication Devices %%%
+//***************************************************************************
+#define SCSI_GET_MSG_6  0x08    // Get Message 6-Byte (MANDATORY)
+#define SCSI_GET_MSG_10 0x28    // Get Message 10-Byte (O)
+#define SCSI_GET_MSG_12 0xA8    // Get Message 12-Byte (O)
+#define SCSI_SND_MSG_6  0x0A    // Send Message 6-Byte (MANDATORY)
+#define SCSI_SND_MSG_10 0x2A    // Send Message 10-Byte (O)
+#define SCSI_SND_MSG_12 0xAA    // Send Message 12-Byte (O)
+
+//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+//
+//                    %%% END OF SCSI COMMAND OPCODES %%%
+//
+///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+
+//***************************************************************************
+//                      %%% Request Sense Data Format %%%
+//***************************************************************************
+typedef struct {
+
+    BYTE    ErrorCode;          // Error Code (70H or 71H)
+    BYTE    SegmentNum;         // Number of current segment descriptor
+    BYTE    SenseKey;           // Sense Key(See bit definitions too)
+    BYTE    InfoByte0;          // Information MSB
+    BYTE    InfoByte1;          // Information MID
+    BYTE    InfoByte2;          // Information MID
+    BYTE    InfoByte3;          // Information LSB
+    BYTE    AddSenLen;          // Additional Sense Length
+    BYTE    ComSpecInf0;        // Command Specific Information MSB
+    BYTE    ComSpecInf1;        // Command Specific Information MID
+    BYTE    ComSpecInf2;        // Command Specific Information MID
+    BYTE    ComSpecInf3;        // Command Specific Information LSB
+    BYTE    AddSenseCode;       // Additional Sense Code
+    BYTE    AddSenQual;         // Additional Sense Code Qualifier
+    BYTE    FieldRepUCode;      // Field Replaceable Unit Code
+    BYTE    SenKeySpec15;       // Sense Key Specific 15th byte
+    BYTE    SenKeySpec16;       // Sense Key Specific 16th byte
+    BYTE    SenKeySpec17;       // Sense Key Specific 17th byte
+    BYTE    AddSenseBytes;      // Additional Sense Bytes
+
+} SENSE_DATA_FMT;
+
+//***************************************************************************
+//                       %%% REQUEST SENSE ERROR CODE %%%
+//***************************************************************************
+#define SERROR_CURRENT  0x70    // Current Errors
+#define SERROR_DEFERED  0x71    // Deferred Errors
+
+//***************************************************************************
+//                   %%% REQUEST SENSE BIT DEFINITIONS %%%
+//***************************************************************************
+#define SENSE_VALID     0x80    // Byte 0 Bit 7
+#define SENSE_FILEMRK   0x80    // Byte 2 Bit 7
+#define SENSE_EOM       0x40    // Byte 2 Bit 6
+#define SENSE_ILI       0x20    // Byte 2 Bit 5
+
+//***************************************************************************
+//               %%% REQUEST SENSE SENSE KEY DEFINITIONS %%%
+//***************************************************************************
+#define KEY_NOSENSE     0x00    // No Sense
+#define KEY_RECERROR    0x01    // Recovered Error
+#define KEY_NOTREADY    0x02    // Not Ready
+#define KEY_MEDIUMERR   0x03    // Medium Error
+#define KEY_HARDERROR   0x04    // Hardware Error
+#define KEY_ILLGLREQ    0x05    // Illegal Request
+#define KEY_UNITATT     0x06    // Unit Attention
+#define KEY_DATAPROT    0x07    // Data Protect
+#define KEY_BLANKCHK    0x08    // Blank Check
+#define KEY_VENDSPEC    0x09    // Vendor Specific
+#define KEY_COPYABORT   0x0A    // Copy Abort
+#define KEY_EQUAL       0x0C    // Equal (Search)
+#define KEY_VOLOVRFLW   0x0D    // Volume Overflow
+#define KEY_MISCOMP     0x0E    // Miscompare (Search)
+#define KEY_RESERVED    0x0F    // Reserved
+
+//***************************************************************************
+//                %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%%
+//***************************************************************************
+#define DTYPE_DASD      0x00    // Disk Device
+#define DTYPE_SEQD      0x01    // Tape Device
+#define DTYPE_PRNT      0x02    // Printer
+#define DTYPE_PROC      0x03    // Processor
+#define DTYPE_WORM      0x04    // Write-once read-multiple
+#define DTYPE_CROM      0x05    // CD-ROM device
+#define DTYPE_CDROM     0x05    // CD-ROM device
+#define DTYPE_SCAN      0x06    // Scanner device
+#define DTYPE_OPTI      0x07    // Optical memory device
+#define DTYPE_JUKE      0x08    // Medium Changer device
+#define DTYPE_COMM      0x09    // Communications device
+#define DTYPE_RESL      0x0A    // Reserved (low)
+#define DTYPE_RESH      0x1E    // Reserved (high)
+#define DTYPE_UNKNOWN   0x1F    // Unknown or no device type
+
+//***************************************************************************
+//                %%% ANSI APPROVED VERSION DEFINITIONS %%%
+//***************************************************************************
+#define ANSI_MAYBE      0x0     // Device may or may not be ANSI approved stand
+#define ANSI_SCSI1      0x1     // Device complies to ANSI X3.131-1986 (SCSI-1)
+#define ANSI_SCSI2      0x2     // Device complies to SCSI-2
+#define ANSI_RESLO      0x3     // Reserved (low)
+#define ANSI_RESHI      0x7     // Reserved (high)
diff --git a/tools/ioemu/iodev/scsipt.h b/tools/ioemu/iodev/scsipt.h
new file mode 100644 (file)
index 0000000..b3c8508
--- /dev/null
@@ -0,0 +1,144 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: scsipt.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//
+// iodev/scsipt.h
+// $Id: scsipt.h,v 1.4 2002/09/16 16:58:36 bdenney Exp $
+//
+// This file was copied from ... ?
+//
+// distilled information from various header files from Microsoft's
+// DDK for Windows NT 4.0
+//
+
+#ifndef _SCSIPT_H_INC
+#define _SCSIPT_H_INC
+
+#include <windows.h>
+
+typedef struct {
+  USHORT Length;
+  UCHAR  ScsiStatus;
+  UCHAR  PathId;
+  UCHAR  TargetId;
+  UCHAR  Lun;
+  UCHAR  CdbLength;
+  UCHAR  SenseInfoLength;
+  UCHAR  DataIn;
+  ULONG  DataTransferLength;
+  ULONG  TimeOutValue;
+  ULONG  DataBufferOffset;
+  ULONG  SenseInfoOffset;
+  UCHAR  Cdb[16];
+} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+
+typedef struct {
+  USHORT Length;
+  UCHAR  ScsiStatus;
+  UCHAR  PathId;
+  UCHAR  TargetId;
+  UCHAR  Lun;
+  UCHAR  CdbLength;
+  UCHAR  SenseInfoLength;
+  UCHAR  DataIn;
+  ULONG  DataTransferLength;
+  ULONG  TimeOutValue;
+  PVOID  DataBuffer;
+  ULONG  SenseInfoOffset;
+  UCHAR  Cdb[16];
+} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+
+
+typedef struct {
+  SCSI_PASS_THROUGH spt;
+  ULONG Filler;
+  UCHAR ucSenseBuf[32];
+  UCHAR ucDataBuf[512];
+} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
+
+
+typedef struct {
+  SCSI_PASS_THROUGH_DIRECT spt;
+  ULONG Filler;
+  UCHAR ucSenseBuf[32];
+} SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
+
+
+
+typedef struct {
+  UCHAR NumberOfLogicalUnits;
+  UCHAR InitiatorBusId;
+  ULONG InquiryDataOffset;
+} SCSI_BUS_DATA, *PSCSI_BUS_DATA;
+
+
+typedef struct {
+  UCHAR NumberOfBusses;
+  SCSI_BUS_DATA BusData[1];
+} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;
+
+
+typedef struct {
+  UCHAR PathId;
+  UCHAR TargetId;
+  UCHAR Lun;
+  BOOLEAN DeviceClaimed;
+  ULONG InquiryDataLength;
+  ULONG NextInquiryDataOffset;
+  UCHAR InquiryData[1];
+} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;
+
+
+typedef struct {
+  ULONG Length;
+  UCHAR PortNumber;
+  UCHAR PathId;
+  UCHAR TargetId;
+  UCHAR Lun;
+} SCSI_ADDRESS, *PSCSI_ADDRESS;
+
+
+/*
+ * method codes
+ */
+#define  METHOD_BUFFERED     0
+#define  METHOD_IN_DIRECT    1
+#define  METHOD_OUT_DIRECT   2
+#define  METHOD_NEITHER      3
+
+/*
+ * file access values
+ */
+#define  FILE_ANY_ACCESS      0
+#define  FILE_READ_ACCESS     (0x0001)
+#define  FILE_WRITE_ACCESS    (0x0002)
+
+
+#define IOCTL_SCSI_BASE    0x00000004
+
+/*
+ * constants for DataIn member of SCSI_PASS_THROUGH* structures
+ */
+#define  SCSI_IOCTL_DATA_OUT          0
+#define  SCSI_IOCTL_DATA_IN           1
+#define  SCSI_IOCTL_DATA_UNSPECIFIED  2
+
+/*
+ * Standard IOCTL define
+ */
+#define CTL_CODE( DevType, Function, Method, Access ) (                 \
+    ((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+
+#define IOCTL_SCSI_PASS_THROUGH         CTL_CODE( IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_MINIPORT             CTL_CODE( IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_GET_INQUIRY_DATA     CTL_CODE( IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_CAPABILITIES     CTL_CODE( IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE( IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS )
+#define IOCTL_SCSI_GET_ADDRESS          CTL_CODE( IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS )
+
+
+
+#endif
diff --git a/tools/ioemu/iodev/serial.cc b/tools/ioemu/iodev/serial.cc
new file mode 100644 (file)
index 0000000..02deec3
--- /dev/null
@@ -0,0 +1,1001 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial.cc,v 1.41 2003/11/09 00:14:43 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Peter Grehan (grehan@iprg.nokia.com) coded the original version of this
+// serial emulation. He implemented a single 8250, and allow terminal
+// input/output to stdout on FreeBSD.
+// The current version emulates a single 16550A with FIFO. Terminal
+// input/output now works on some more platforms.
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theSerialDevice->
+
+#if USE_RAW_SERIAL
+#include <signal.h>
+#endif
+
+#ifdef WIN32
+#ifndef __MINGW32__
+// +++
+//#include <winsock2.h>
+#include <winsock.h>
+#endif
+#endif
+
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__GNU__) || defined(__APPLE__)
+#define SERIAL_ENABLE
+#endif
+
+#ifdef SERIAL_ENABLE
+extern "C" {
+#include <termios.h>
+};
+#endif
+
+#ifdef SERIAL_ENABLE
+static struct termios term_orig, term_new;
+#endif
+
+static int tty_id;
+
+bx_serial_c *theSerialDevice = NULL;
+
+  int
+libserial_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theSerialDevice = new bx_serial_c ();
+  bx_devices.pluginSerialDevice = theSerialDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theSerialDevice, BX_PLUGIN_SERIAL);
+  return(0); // Success
+}
+
+  void
+libserial_LTX_plugin_fini(void)
+{
+}
+
+bx_serial_c::bx_serial_c(void)
+{
+  put("SER");
+  settype(SERLOG);
+  tty_id = -1;
+  for (int i=0; i<BX_SERIAL_MAXDEV; i++) {
+    s[i].tx_timer_index = BX_NULL_TIMER_HANDLE;
+    s[i].rx_timer_index = BX_NULL_TIMER_HANDLE;
+    s[i].fifo_timer_index = BX_NULL_TIMER_HANDLE;
+  }
+}
+
+bx_serial_c::~bx_serial_c(void)
+{
+#ifdef SERIAL_ENABLE
+  if ((bx_options.com[0].Oenabled->get ()) && (tty_id >= 0))
+    tcsetattr(tty_id, TCSAFLUSH, &term_orig);
+#endif
+  // nothing for now
+}
+
+
+  void
+bx_serial_c::init(void)
+{
+  Bit16u ports[BX_SERIAL_MAXDEV] = {0x03f8, 0x02f8, 0x03e8, 0x02e8};
+  char name[16];
+
+  if (!bx_options.com[0].Oenabled->get ())
+    return;
+
+#ifdef SERIAL_ENABLE
+  if (strlen(bx_options.com[0].Odev->getptr ()) > 0) {
+    tty_id = open(bx_options.com[0].Odev->getptr (), O_RDWR|O_NONBLOCK,600);
+    if (tty_id < 0)
+      BX_PANIC(("open of %s (%s) failed\n",
+                "com1", bx_options.com[0].Odev->getptr ()));
+    BX_DEBUG(("tty_id: %d",tty_id));
+    tcgetattr(tty_id, &term_orig);
+    bcopy((caddr_t) &term_orig, (caddr_t) &term_new, sizeof(struct termios));
+    cfmakeraw(&term_new);
+    term_new.c_oflag |= OPOST | ONLCR;  // Enable NL to CR-NL translation
+#ifndef TRUE_CTLC
+    // ctl-C will exit Bochs, or trap to the debugger
+    term_new.c_iflag &= ~IGNBRK;
+    term_new.c_iflag |= BRKINT;
+    term_new.c_lflag |= ISIG;
+#else
+    // ctl-C will be delivered to the serial port
+    term_new.c_iflag |= IGNBRK;
+    term_new.c_iflag &= ~BRKINT;
+#endif    /* !def TRUE_CTLC */
+    term_new.c_iflag = 0;
+    term_new.c_oflag = 0;
+    term_new.c_cflag = CS8|CREAD|CLOCAL;
+    term_new.c_lflag = 0;
+    term_new.c_cc[VMIN] = 1;
+    term_new.c_cc[VTIME] = 0;
+    //term_new.c_iflag |= IXOFF;
+    tcsetattr(tty_id, TCSAFLUSH, &term_new);
+  }
+#endif   /* def SERIAL_ENABLE */
+  // nothing for now
+#if USE_RAW_SERIAL
+  this->raw = new serial_raw("/dev/cua0", SIGUSR1);
+#endif // USE_RAW_SERIAL
+
+  /*
+   * Put the UART registers into their RESET state
+   */
+  for (unsigned i=0; i<BX_N_SERIAL_PORTS; i++) {
+    if (bx_options.com[i].Oenabled->get ()) {
+      sprintf(name, "Serial Port %d", i + 1);
+      /* serial interrupt */
+      BX_SER_THIS s[i].IRQ = 4 - (i & 1);
+      if (i < 2) {
+        DEV_register_irq(BX_SER_THIS s[i].IRQ, name);
+      }
+      /* internal state */
+      BX_SER_THIS s[i].ls_ipending = 0;
+      BX_SER_THIS s[i].ms_ipending = 0;
+      BX_SER_THIS s[i].rx_ipending = 0;
+      BX_SER_THIS s[i].fifo_ipending = 0;
+      BX_SER_THIS s[i].ls_interrupt = 0;
+      BX_SER_THIS s[i].ms_interrupt = 0;
+      BX_SER_THIS s[i].rx_interrupt = 0;
+      BX_SER_THIS s[i].tx_interrupt = 0;
+      BX_SER_THIS s[i].fifo_interrupt = 0;
+
+      if (BX_SER_THIS s[i].tx_timer_index == BX_NULL_TIMER_HANDLE) {
+        BX_SER_THIS s[i].tx_timer_index =
+          bx_pc_system.register_timer(this, tx_timer_handler, 0,
+                                      0,0, "serial.tx"); // one-shot, inactive
+      }
+
+      if (BX_SER_THIS s[i].rx_timer_index == BX_NULL_TIMER_HANDLE) {
+        BX_SER_THIS s[i].rx_timer_index =
+          bx_pc_system.register_timer(this, rx_timer_handler, 0,
+                                      0,0, "serial.rx"); // one-shot, inactive
+      }
+      if (BX_SER_THIS s[i].fifo_timer_index == BX_NULL_TIMER_HANDLE) {
+        BX_SER_THIS s[i].fifo_timer_index =
+          bx_pc_system.register_timer(this, fifo_timer_handler, 0,
+                                      0,0, "serial.fifo"); // one-shot, inactive
+      }
+      BX_SER_THIS s[i].rx_pollstate = BX_SER_RXIDLE;
+
+      /* int enable: b0000 0000 */
+      BX_SER_THIS s[i].int_enable.rxdata_enable = 0;
+      BX_SER_THIS s[i].int_enable.txhold_enable = 0;
+      BX_SER_THIS s[i].int_enable.rxlstat_enable = 0;
+      BX_SER_THIS s[i].int_enable.modstat_enable = 0;
+
+      /* int ID: b0000 0001 */
+      BX_SER_THIS s[i].int_ident.ipending = 1;
+      BX_SER_THIS s[i].int_ident.int_ID = 0;
+
+      /* FIFO control: b0000 0000 */
+      BX_SER_THIS s[i].fifo_cntl.enable = 0;
+      BX_SER_THIS s[i].fifo_cntl.rxtrigger = 0;
+      BX_SER_THIS s[i].rx_fifo_end = 0;
+      BX_SER_THIS s[i].tx_fifo_end = 0;
+
+      /* Line Control reg: b0000 0000 */
+      BX_SER_THIS s[i].line_cntl.wordlen_sel = 0;
+      BX_SER_THIS s[i].line_cntl.stopbits = 0;
+      BX_SER_THIS s[i].line_cntl.parity_enable = 0;
+      BX_SER_THIS s[i].line_cntl.evenparity_sel = 0;
+      BX_SER_THIS s[i].line_cntl.stick_parity = 0;
+      BX_SER_THIS s[i].line_cntl.break_cntl = 0;
+      BX_SER_THIS s[i].line_cntl.dlab = 0;
+
+      /* Modem Control reg: b0000 0000 */
+      BX_SER_THIS s[i].modem_cntl.dtr = 0;
+      BX_SER_THIS s[i].modem_cntl.rts = 0;
+      BX_SER_THIS s[i].modem_cntl.out1 = 0;
+      BX_SER_THIS s[i].modem_cntl.out2 = 0;
+      BX_SER_THIS s[i].modem_cntl.local_loopback = 0;
+
+      /* Line Status register: b0110 0000 */
+      BX_SER_THIS s[i].line_status.rxdata_ready = 0;
+      BX_SER_THIS s[i].line_status.overrun_error = 0;
+      BX_SER_THIS s[i].line_status.parity_error = 0;
+      BX_SER_THIS s[i].line_status.framing_error = 0;
+      BX_SER_THIS s[i].line_status.break_int = 0;
+      BX_SER_THIS s[i].line_status.thr_empty = 1;
+      BX_SER_THIS s[i].line_status.tsr_empty = 1;
+      BX_SER_THIS s[i].line_status.fifo_error = 0;
+
+      /* Modem Status register: bXXXX 0000 */
+      BX_SER_THIS s[i].modem_status.delta_cts = 0;
+      BX_SER_THIS s[i].modem_status.delta_dsr = 0;
+      BX_SER_THIS s[i].modem_status.ri_trailedge = 0;
+      BX_SER_THIS s[i].modem_status.delta_dcd = 0;
+      BX_SER_THIS s[i].modem_status.cts = 0;
+      BX_SER_THIS s[i].modem_status.dsr = 0;
+      BX_SER_THIS s[i].modem_status.ri = 0;
+      BX_SER_THIS s[i].modem_status.dcd = 0;
+
+      BX_SER_THIS s[i].scratch = 0;      /* scratch register */
+      BX_SER_THIS s[i].divisor_lsb = 1;  /* divisor-lsb register */
+      BX_SER_THIS s[i].divisor_msb = 0;  /* divisor-msb register */
+
+      BX_SER_THIS s[i].baudrate = 115200;
+
+      for (unsigned addr=ports[i]; addr<(unsigned)(ports[i]+8); addr++) {
+        BX_DEBUG(("register read/write: 0x%04x",addr));
+        DEV_register_ioread_handler(this, read_handler, addr, name, 1);
+        DEV_register_iowrite_handler(this, write_handler, addr, name, 1);
+      }
+      BX_INFO(("com%d at 0x%04x irq %d", i+1, ports[i], BX_SER_THIS s[i].IRQ));
+    }
+  }
+}
+
+  void
+bx_serial_c::reset(unsigned type)
+{
+}
+
+  void
+bx_serial_c::lower_interrupt(Bit8u port)
+{
+  /* If there are no more ints pending, clear the irq */
+  if ((BX_SER_THIS s[port].rx_interrupt == 0) &&
+      (BX_SER_THIS s[port].tx_interrupt == 0) &&
+      (BX_SER_THIS s[port].ls_interrupt == 0) &&
+      (BX_SER_THIS s[port].ms_interrupt == 0) &&
+      (BX_SER_THIS s[port].fifo_interrupt == 0)) {
+    DEV_pic_lower_irq(BX_SER_THIS s[port].IRQ);
+  }
+}
+
+  void
+bx_serial_c::raise_interrupt(Bit8u port, int type)
+{
+  bx_bool gen_int = 0;
+
+  switch (type) {
+    case BX_SER_INT_IER: /* IER has changed */
+      gen_int = 1;
+      break;
+    case BX_SER_INT_RXDATA:
+      if (BX_SER_THIS s[port].int_enable.rxdata_enable) {
+        BX_SER_THIS s[port].rx_interrupt = 1;
+        gen_int = 1;
+      } else {
+        BX_SER_THIS s[port].rx_ipending = 1;
+      }
+      break;
+    case BX_SER_INT_TXHOLD:
+      if (BX_SER_THIS s[port].int_enable.txhold_enable) {
+        BX_SER_THIS s[port].tx_interrupt = 1;
+        gen_int = 1;
+      }
+      break;
+    case BX_SER_INT_RXLSTAT:
+      if (BX_SER_THIS s[port].int_enable.rxlstat_enable) {
+        BX_SER_THIS s[port].ls_interrupt = 1;
+        gen_int = 1;
+      } else {
+        BX_SER_THIS s[port].ls_ipending = 1;
+      }
+      break;
+    case BX_SER_INT_MODSTAT:
+      if ((BX_SER_THIS s[port].ms_ipending == 1) &&
+          (BX_SER_THIS s[port].int_enable.modstat_enable == 1)) {
+        BX_SER_THIS s[port].ms_interrupt = 1;
+        BX_SER_THIS s[port].ms_ipending = 0;
+        gen_int = 1;
+      }
+      break;
+    case BX_SER_INT_FIFO:
+      if (BX_SER_THIS s[port].int_enable.rxdata_enable) {
+        BX_SER_THIS s[port].fifo_interrupt = 1;
+        gen_int = 1;
+      } else {
+        BX_SER_THIS s[port].fifo_ipending = 1;
+      }
+      break;
+  }
+  if (gen_int && BX_SER_THIS s[port].modem_cntl.out2) {
+    DEV_pic_raise_irq(BX_SER_THIS s[port].IRQ);
+  }
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_serial_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_SER_SMF
+  bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_serial_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_SER_SMF
+  //UNUSED(address);
+  Bit8u val;
+
+  /* SERIAL PORT 1 */
+
+  BX_DEBUG(("register read from address 0x%04x - ", (unsigned) address));
+
+  switch (address) {
+    case 0x03F8: /* receive buffer, or divisor latch LSB if DLAB set */
+      if (BX_SER_THIS s[0].line_cntl.dlab) {
+        val = BX_SER_THIS s[0].divisor_lsb;
+      } else {
+        if (BX_SER_THIS s[0].fifo_cntl.enable) {
+          val = BX_SER_THIS s[0].rx_fifo[0];
+          if (BX_SER_THIS s[0].rx_fifo_end > 0) {
+            memcpy(&BX_SER_THIS s[0].rx_fifo[0], &BX_SER_THIS s[0].rx_fifo[1], 15);
+            BX_SER_THIS s[0].rx_fifo_end--;
+          }
+          if (BX_SER_THIS s[0].rx_fifo_end == 0) {
+            BX_SER_THIS s[0].line_status.rxdata_ready = 0;
+            BX_SER_THIS s[0].rx_interrupt = 0;
+            BX_SER_THIS s[0].rx_ipending = 0;
+            BX_SER_THIS s[0].fifo_interrupt = 0;
+            BX_SER_THIS s[0].fifo_ipending = 0;
+            lower_interrupt(0);
+          }
+        } else {
+          val = BX_SER_THIS s[0].rxbuffer;
+          BX_SER_THIS s[0].line_status.rxdata_ready = 0;
+          BX_SER_THIS s[0].rx_interrupt = 0;
+          BX_SER_THIS s[0].rx_ipending = 0;
+          lower_interrupt(0);
+        }
+      }
+      break;
+
+    case 0x03F9: /* interrupt enable register, or div. latch MSB */
+      if (BX_SER_THIS s[0].line_cntl.dlab) {
+        val = BX_SER_THIS s[0].divisor_msb;
+      } else {
+        val = BX_SER_THIS s[0].int_enable.rxdata_enable |
+              (BX_SER_THIS s[0].int_enable.txhold_enable  << 1) |
+              (BX_SER_THIS s[0].int_enable.rxlstat_enable << 2) |
+              (BX_SER_THIS s[0].int_enable.modstat_enable << 3);
+      }
+      break;
+
+    case 0x03FA: /* interrupt ID register */
+      /*
+       * Set the interrupt ID based on interrupt source
+       */
+      if (BX_SER_THIS s[0].ls_interrupt) {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x3;
+        BX_SER_THIS s[0].int_ident.ipending = 0;
+      } else if (BX_SER_THIS s[0].fifo_interrupt) {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x6;
+        BX_SER_THIS s[0].int_ident.ipending = 0;
+      } else if (BX_SER_THIS s[0].rx_interrupt) {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x2;
+        BX_SER_THIS s[0].int_ident.ipending = 0;
+      } else if (BX_SER_THIS s[0].tx_interrupt) {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x1;
+        BX_SER_THIS s[0].int_ident.ipending = 0;
+      } else if (BX_SER_THIS s[0].ms_interrupt) {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x0;
+        BX_SER_THIS s[0].int_ident.ipending = 0;
+      } else {
+        BX_SER_THIS s[0].int_ident.int_ID = 0x0;
+        BX_SER_THIS s[0].int_ident.ipending = 1;
+      }
+      BX_SER_THIS s[0].tx_interrupt = 0;
+      lower_interrupt(0);
+
+      val = BX_SER_THIS s[0].int_ident.ipending  |
+            (BX_SER_THIS s[0].int_ident.int_ID << 1) |
+            (BX_SER_THIS s[0].fifo_cntl.enable ? 0xc0 : 0x00);
+      break;
+
+    case 0x03FB: /* Line control register */
+      val = BX_SER_THIS s[0].line_cntl.wordlen_sel       |
+       (BX_SER_THIS s[0].line_cntl.stopbits       << 2) |
+       (BX_SER_THIS s[0].line_cntl.parity_enable  << 3) |
+       (BX_SER_THIS s[0].line_cntl.evenparity_sel << 4) |
+       (BX_SER_THIS s[0].line_cntl.stick_parity   << 5) |
+       (BX_SER_THIS s[0].line_cntl.break_cntl     << 6) |
+       (BX_SER_THIS s[0].line_cntl.dlab           << 7);
+      break;
+
+    case 0x03FC: /* MODEM control register */
+      val = BX_SER_THIS s[0].modem_cntl.dtr |
+            (BX_SER_THIS s[0].modem_cntl.rts << 1) |
+            (BX_SER_THIS s[0].modem_cntl.out1 << 2) |
+            (BX_SER_THIS s[0].modem_cntl.out2 << 3) |
+            (BX_SER_THIS s[0].modem_cntl.local_loopback << 4);
+      break;
+
+    case 0x03FD: /* Line status register */
+      val = BX_SER_THIS s[0].line_status.rxdata_ready     |
+       (BX_SER_THIS s[0].line_status.overrun_error  << 1) |
+       (BX_SER_THIS s[0].line_status.parity_error   << 2) |
+       (BX_SER_THIS s[0].line_status.framing_error  << 3) |
+       (BX_SER_THIS s[0].line_status.break_int      << 4) |
+       (BX_SER_THIS s[0].line_status.thr_empty      << 5) |
+       (BX_SER_THIS s[0].line_status.tsr_empty      << 6) |
+       (BX_SER_THIS s[0].line_status.fifo_error     << 7);
+      BX_SER_THIS s[0].line_status.overrun_error = 0;
+      BX_SER_THIS s[0].line_status.break_int = 0;
+      BX_SER_THIS s[0].ls_interrupt = 0;
+      BX_SER_THIS s[0].ls_ipending = 0;
+      lower_interrupt(0);
+      break;
+
+    case 0x03FE: /* MODEM status register */
+      val = BX_SER_THIS s[0].modem_status.delta_cts       |
+       (BX_SER_THIS s[0].modem_status.delta_dsr    << 1) |
+       (BX_SER_THIS s[0].modem_status.ri_trailedge << 2) |
+       (BX_SER_THIS s[0].modem_status.delta_dcd    << 3) |
+       (BX_SER_THIS s[0].modem_status.cts          << 4) |
+       (BX_SER_THIS s[0].modem_status.dsr          << 5) |
+       (BX_SER_THIS s[0].modem_status.ri           << 6) |
+       (BX_SER_THIS s[0].modem_status.dcd          << 7);
+      BX_SER_THIS s[0].modem_status.delta_cts = 0;
+      BX_SER_THIS s[0].modem_status.delta_dsr = 0;
+      BX_SER_THIS s[0].modem_status.ri_trailedge = 0;
+      BX_SER_THIS s[0].modem_status.delta_dcd = 0;
+      BX_SER_THIS s[0].ms_interrupt = 0;
+      BX_SER_THIS s[0].ms_ipending = 0;
+      lower_interrupt(0);
+      break;
+
+    case 0x03FF: /* scratch register */
+      val = BX_SER_THIS s[0].scratch;
+      break;
+
+    default:
+      val = 0; // keep compiler happy
+      BX_PANIC(("unsupported io read from address=0x%04x!",
+        (unsigned) address));
+      break;
+  }
+
+  BX_DEBUG(("val =  0x%02x", (unsigned) val));
+
+  return(val);
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+void
+bx_serial_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_SER_SMF
+  bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+void
+bx_serial_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_SER_SMF
+  bx_bool prev_cts, prev_dsr, prev_ri, prev_dcd;
+  bx_bool new_rx_ien, new_tx_ien, new_ls_ien, new_ms_ien;
+  bx_bool gen_int = 0;
+
+  /* SERIAL PORT 1 */
+
+  BX_DEBUG(("write to address: 0x%04x = 0x%02x",
+             (unsigned) address, (unsigned) value));
+
+  switch (address) {
+    case 0x03F8: /* transmit buffer, or divisor latch LSB if DLAB set */
+      if (BX_SER_THIS s[0].line_cntl.dlab) {
+       BX_SER_THIS s[0].divisor_lsb = value;
+
+        if ((value != 0) || (BX_SER_THIS s[0].divisor_msb != 0)) {
+         BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL /
+                         (16 * ((BX_SER_THIS s[0].divisor_msb << 8) |
+                                BX_SER_THIS s[0].divisor_lsb)));
+#if USE_RAW_SERIAL
+         BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate);
+#endif // USE_RAW_SERIAL
+       }
+      } else {
+        Bit8u bitmask = 0xff >> (3 - BX_SER_THIS s[0].line_cntl.wordlen_sel);
+        if (BX_SER_THIS s[0].line_status.thr_empty) {
+          if (BX_SER_THIS s[0].fifo_cntl.enable) {
+            BX_SER_THIS s[0].tx_fifo[BX_SER_THIS s[0].tx_fifo_end++] = value & bitmask;
+          } else {
+            BX_SER_THIS s[0].thrbuffer = value & bitmask;
+          }
+          BX_SER_THIS s[0].line_status.thr_empty = 0;
+          if (BX_SER_THIS s[0].line_status.tsr_empty) {
+            if (BX_SER_THIS s[0].fifo_cntl.enable) {
+              BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].tx_fifo[0];
+              memcpy(&BX_SER_THIS s[0].tx_fifo[0], &BX_SER_THIS s[0].tx_fifo[1], 15);
+              BX_SER_THIS s[0].line_status.thr_empty = (--BX_SER_THIS s[0].tx_fifo_end == 0);
+            } else {
+              BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].thrbuffer;
+              BX_SER_THIS s[0].line_status.thr_empty = 1;
+            }
+            BX_SER_THIS s[0].line_status.tsr_empty = 0;
+            raise_interrupt(0, BX_SER_INT_TXHOLD);
+            bx_pc_system.activate_timer(BX_SER_THIS s[0].tx_timer_index,
+                                        (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+                                        (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+                                        0); /* not continuous */
+          } else {
+            BX_SER_THIS s[0].tx_interrupt = 0;
+            lower_interrupt(0);
+          }
+        } else {
+          if (BX_SER_THIS s[0].fifo_cntl.enable) {
+            if (BX_SER_THIS s[0].tx_fifo_end < 16) {
+              BX_SER_THIS s[0].tx_fifo[BX_SER_THIS s[0].tx_fifo_end++] = value & bitmask;
+            } else {
+              BX_ERROR(("com1: transmit FIFO overflow"));
+            }
+          } else {
+            BX_ERROR(("write to tx hold register when not empty"));
+          }
+        }
+      }
+      break;
+
+    case 0x03F9: /* interrupt enable register, or div. latch MSB */
+      if (BX_SER_THIS s[0].line_cntl.dlab) {
+       BX_SER_THIS s[0].divisor_msb = value;
+
+        if ((value != 0) || (BX_SER_THIS s[0].divisor_lsb != 0)) {
+         BX_SER_THIS s[0].baudrate = (int) (BX_PC_CLOCK_XTL /
+                      (16 * ((BX_SER_THIS s[0].divisor_msb << 8) |
+                             BX_SER_THIS s[0].divisor_lsb)));
+#if USE_RAW_SERIAL
+         BX_SER_THIS raw->set_baudrate(BX_SER_THIS s[0].baudrate);
+#endif // USE_RAW_SERIAL
+       }
+      } else {
+       new_rx_ien = value & 0x01;
+       new_tx_ien = (value & 0x02) >> 1;
+       new_ls_ien = (value & 0x04) >> 2;
+       new_ms_ien = (value & 0x08) >> 3;
+        if (new_ms_ien != BX_SER_THIS s[0].int_enable.modstat_enable) {
+          BX_SER_THIS s[0].int_enable.modstat_enable  = new_ms_ien;
+          if (BX_SER_THIS s[0].int_enable.modstat_enable == 1) {
+            if (BX_SER_THIS s[0].ms_ipending == 1) {
+              BX_SER_THIS s[0].ms_interrupt = 1;
+              BX_SER_THIS s[0].ms_ipending = 0;
+              gen_int = 1;
+            }
+          } else {
+            if (BX_SER_THIS s[0].ms_interrupt == 1) {
+              BX_SER_THIS s[0].ms_interrupt = 0;
+              BX_SER_THIS s[0].ms_ipending = 1;
+              lower_interrupt(0);
+            }
+          }
+        }
+        if (new_tx_ien != BX_SER_THIS s[0].int_enable.txhold_enable) {
+          BX_SER_THIS s[0].int_enable.txhold_enable  = new_tx_ien;
+          if (BX_SER_THIS s[0].int_enable.txhold_enable == 1) {
+            BX_SER_THIS s[0].tx_interrupt = BX_SER_THIS s[0].line_status.thr_empty;
+            if (BX_SER_THIS s[0].tx_interrupt) gen_int = 1;
+          } else {
+            BX_SER_THIS s[0].tx_interrupt = 0;
+            lower_interrupt(0);
+          }
+        }
+        if (new_rx_ien != BX_SER_THIS s[0].int_enable.rxdata_enable) {
+          BX_SER_THIS s[0].int_enable.rxdata_enable  = new_rx_ien;
+          if (BX_SER_THIS s[0].int_enable.rxdata_enable == 1) {
+            if (BX_SER_THIS s[0].fifo_ipending == 1) {
+              BX_SER_THIS s[0].fifo_interrupt = 1;
+              BX_SER_THIS s[0].fifo_ipending = 0;
+              gen_int = 1;
+            }
+            if (BX_SER_THIS s[0].rx_ipending == 1) {
+              BX_SER_THIS s[0].rx_interrupt = 1;
+              BX_SER_THIS s[0].rx_ipending = 0;
+              gen_int = 1;
+            }
+          } else {
+            if (BX_SER_THIS s[0].rx_interrupt == 1) {
+              BX_SER_THIS s[0].rx_interrupt = 0;
+              BX_SER_THIS s[0].rx_ipending = 1;
+              lower_interrupt(0);
+            }
+            if (BX_SER_THIS s[0].fifo_interrupt == 1) {
+              BX_SER_THIS s[0].fifo_interrupt = 0;
+              BX_SER_THIS s[0].fifo_ipending = 1;
+              lower_interrupt(0);
+            }
+          }
+        }
+        if (new_ls_ien != BX_SER_THIS s[0].int_enable.rxlstat_enable) {
+          BX_SER_THIS s[0].int_enable.rxlstat_enable  = new_ls_ien;
+          if (BX_SER_THIS s[0].int_enable.rxlstat_enable == 1) {
+            if (BX_SER_THIS s[0].ls_ipending == 1) {
+              BX_SER_THIS s[0].ls_interrupt = 1;
+              BX_SER_THIS s[0].ls_ipending = 0;
+              gen_int = 1;
+            }
+          } else {
+            if (BX_SER_THIS s[0].ls_interrupt == 1) {
+              BX_SER_THIS s[0].ls_interrupt = 0;
+              BX_SER_THIS s[0].ls_ipending = 1;
+              lower_interrupt(0);
+            }
+          }
+        }
+        if (gen_int) raise_interrupt(0, BX_SER_INT_IER);
+      }
+      break;
+
+    case 0x03FA: /* FIFO control register */
+      if (!BX_SER_THIS s[0].fifo_cntl.enable && (value & 0x01)) {
+        BX_INFO(("FIFO enabled"));
+        BX_SER_THIS s[0].rx_fifo_end = 0;
+        BX_SER_THIS s[0].tx_fifo_end = 0;
+      }
+      BX_SER_THIS s[0].fifo_cntl.enable = value & 0x01;
+      if (value & 0x02) {
+        BX_SER_THIS s[0].rx_fifo_end = 0;
+      }
+      if (value & 0x04) {
+        BX_SER_THIS s[0].tx_fifo_end = 0;
+      }
+      BX_SER_THIS s[0].fifo_cntl.rxtrigger = (value & 0xc0) >> 6;
+      break;
+
+    case 0x03FB: /* Line control register */
+#if !USE_RAW_SERIAL
+      if ((value & 0x3) != 0x3) {
+       /* ignore this: this is set by FreeBSD when the console
+          code wants to set DLAB */
+      }
+#endif // !USE_RAW_SERIAL
+#if USE_RAW_SERIAL
+      if (BX_SER_THIS s[0].line_cntl.wordlen_sel != (value & 0x3)) {
+           BX_SER_THIS raw->set_data_bits((value & 0x3) + 5);
+      }
+      if (BX_SER_THIS s[0].line_cntl.stopbits != (value & 0x4) >> 2) {
+           BX_SER_THIS raw->set_stop_bits((value & 0x4 >> 2) ? 2 : 1);
+      }
+      if (BX_SER_THIS s[0].line_cntl.parity_enable != (value & 0x8) >> 3 ||
+         BX_SER_THIS s[0].line_cntl.evenparity_sel != (value & 0x10) >> 4 ||
+         BX_SER_THIS s[0].line_cntl.stick_parity != (value & 0x20) >> 5) {
+           if (((value & 0x20) >> 5) &&
+               ((value & 0x8) >> 3))
+                 BX_PANIC(("sticky parity set and parity enabled"));
+           BX_SER_THIS raw->set_parity_mode(((value & 0x8) >> 3),
+                                            ((value & 0x10) >> 4) ? P_EVEN : P_ODD);
+      }
+      if (BX_SER_THIS s[0].line_cntl.break_cntl && !((value & 0x40) >> 6)) {
+           BX_SER_THIS raw->transmit(C_BREAK);
+      }
+#endif // USE_RAW_SERIAL
+
+      BX_SER_THIS s[0].line_cntl.wordlen_sel = value & 0x3;
+      /* These are ignored, but set them up so they can be read back */
+      BX_SER_THIS s[0].line_cntl.stopbits = (value & 0x4) >> 2;
+      BX_SER_THIS s[0].line_cntl.parity_enable = (value & 0x8) >> 3;
+      BX_SER_THIS s[0].line_cntl.evenparity_sel = (value & 0x10) >> 4;
+      BX_SER_THIS s[0].line_cntl.stick_parity = (value & 0x20) >> 5;
+      BX_SER_THIS s[0].line_cntl.break_cntl = (value & 0x40) >> 6;
+      /* used when doing future writes */
+      if (BX_SER_THIS s[0].line_cntl.dlab &&
+         !((value & 0x80) >> 7)) {
+       // Start the receive polling process if not already started
+       // and there is a valid baudrate.
+       if (BX_SER_THIS s[0].rx_pollstate == BX_SER_RXIDLE &&
+           BX_SER_THIS s[0].baudrate != 0) {
+         BX_SER_THIS s[0].rx_pollstate = BX_SER_RXPOLL;
+         bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index,
+                     (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+                      (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+                      0); /* not continuous */
+       }
+       BX_DEBUG(("baud rate set - %d", BX_SER_THIS s[0].baudrate));
+      }
+      BX_SER_THIS s[0].line_cntl.dlab = (value & 0x80) >> 7;
+      break;
+
+    case 0x03FC: /* MODEM control register */
+      if ((value & 0x01) == 0) {
+#if USE_RAW_SERIAL
+       BX_SER_THIS raw->send_hangup();
+#endif
+      }
+
+      BX_SER_THIS s[0].modem_cntl.dtr  = value & 0x01;
+      BX_SER_THIS s[0].modem_cntl.rts  = (value & 0x02) >> 1;
+      BX_SER_THIS s[0].modem_cntl.out1 = (value & 0x04) >> 2;
+      BX_SER_THIS s[0].modem_cntl.out2 = (value & 0x08) >> 3;
+      BX_SER_THIS s[0].modem_cntl.local_loopback = (value & 0x10) >> 4;
+
+      if (BX_SER_THIS s[0].modem_cntl.local_loopback) {
+        prev_cts = BX_SER_THIS s[0].modem_status.cts;
+        prev_dsr = BX_SER_THIS s[0].modem_status.dsr;
+        prev_ri  = BX_SER_THIS s[0].modem_status.ri;
+        prev_dcd = BX_SER_THIS s[0].modem_status.dcd;
+        BX_SER_THIS s[0].modem_status.cts = BX_SER_THIS s[0].modem_cntl.rts;
+        BX_SER_THIS s[0].modem_status.dsr = BX_SER_THIS s[0].modem_cntl.dtr;
+        BX_SER_THIS s[0].modem_status.ri  = BX_SER_THIS s[0].modem_cntl.out1;
+        BX_SER_THIS s[0].modem_status.dcd = BX_SER_THIS s[0].modem_cntl.out2;
+        if (BX_SER_THIS s[0].modem_status.cts != prev_cts) {
+          BX_SER_THIS s[0].modem_status.delta_cts = 1;
+          BX_SER_THIS s[0].ms_ipending = 1;
+        }
+        if (BX_SER_THIS s[0].modem_status.dsr != prev_dsr) {
+          BX_SER_THIS s[0].modem_status.delta_dsr = 1;
+          BX_SER_THIS s[0].ms_ipending = 1;
+        }
+        if (BX_SER_THIS s[0].modem_status.ri != prev_ri)
+          BX_SER_THIS s[0].ms_ipending = 1;
+        if ((BX_SER_THIS s[0].modem_status.ri == 0) && (prev_ri == 1))
+          BX_SER_THIS s[0].modem_status.ri_trailedge = 1;
+        if (BX_SER_THIS s[0].modem_status.dcd != prev_dcd) {
+          BX_SER_THIS s[0].modem_status.delta_dcd = 1;
+          BX_SER_THIS s[0].ms_ipending = 1;
+        }
+        raise_interrupt(0, BX_SER_INT_MODSTAT);
+      } else {
+        /* set these to 0 for the time being */
+        BX_SER_THIS s[0].modem_status.cts = 0;
+        BX_SER_THIS s[0].modem_status.dsr = 0;
+        BX_SER_THIS s[0].modem_status.ri  = 0;
+        BX_SER_THIS s[0].modem_status.dcd = 0;
+      }
+      break;
+
+    case 0x03FD: /* Line status register */
+      BX_ERROR(("write to line status register ignored"));
+      break;
+
+    case 0x03FE: /* MODEM status register */
+      BX_ERROR(("write to MODEM status register ignored"));
+      break;
+
+    case 0x03FF: /* scratch register */
+      BX_SER_THIS s[0].scratch = value;
+      break;
+
+    default:
+      BX_PANIC(("unsupported io write to address=0x%04x, value = 0x%02x!",
+        (unsigned) address, (unsigned) value));
+      break;
+  }
+}
+
+
+void
+bx_serial_c::rx_fifo_enq(Bit8u port, Bit8u data)
+{
+  bx_bool gen_int = 0;
+
+  if (BX_SER_THIS s[port].fifo_cntl.enable) {
+    if (BX_SER_THIS s[port].rx_fifo_end == 16) {
+      BX_ERROR(("com%d: receive FIFO overflow", port + 1));
+      BX_SER_THIS s[port].line_status.overrun_error = 1;
+      raise_interrupt(port, BX_SER_INT_RXLSTAT);
+    } else {
+      BX_SER_THIS s[port].rx_fifo[BX_SER_THIS s[0].rx_fifo_end++] = data;
+      switch (BX_SER_THIS s[port].fifo_cntl.rxtrigger) {
+        case 1:
+          if (BX_SER_THIS s[0].rx_fifo_end == 4) gen_int = 1;
+          break;
+        case 2:
+          if (BX_SER_THIS s[0].rx_fifo_end == 8) gen_int = 1;
+          break;
+        case 3:
+          if (BX_SER_THIS s[0].rx_fifo_end == 14) gen_int = 1;
+          break;
+        default:
+          gen_int = 1;
+      }
+      if (gen_int) {
+        bx_pc_system.deactivate_timer(BX_SER_THIS s[0].fifo_timer_index);
+        BX_SER_THIS s[port].line_status.rxdata_ready = 1;
+        raise_interrupt(port, BX_SER_INT_RXDATA);
+      } else {
+        bx_pc_system.activate_timer(BX_SER_THIS s[0].fifo_timer_index,
+                                    (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+                                    (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5) * 16),
+                                    0); /* not continuous */
+      }
+    }
+  } else {
+    if (BX_SER_THIS s[port].line_status.rxdata_ready == 1) {
+      BX_ERROR(("com%d: overrun error", port + 1));
+      BX_SER_THIS s[port].line_status.overrun_error = 1;
+      raise_interrupt(port, BX_SER_INT_RXLSTAT);
+    }
+    BX_SER_THIS s[port].rxbuffer = data;
+    BX_SER_THIS s[port].line_status.rxdata_ready = 1;
+    raise_interrupt(port, BX_SER_INT_RXDATA);
+  }
+}
+
+
+void
+bx_serial_c::tx_timer_handler(void *this_ptr)
+{
+  bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+  class_ptr->tx_timer();
+}
+
+
+void
+bx_serial_c::tx_timer(void)
+{
+  bx_bool gen_int = 0;
+
+  if (BX_SER_THIS s[0].modem_cntl.local_loopback) {
+    rx_fifo_enq(0, BX_SER_THIS s[0].tsrbuffer);
+  } else {
+#if USE_RAW_SERIAL
+    if (!BX_SER_THIS raw->ready_transmit())
+         BX_PANIC(("Not ready to transmit"));
+    BX_SER_THIS raw->transmit(BX_SER_THIS s[0].tsrbuffer);
+#endif
+#if defined(SERIAL_ENABLE)
+    BX_DEBUG(("write: '%c'", BX_SER_THIS s[0].tsrbuffer));
+    if (tty_id >= 0) write(tty_id, (bx_ptr_t) & BX_SER_THIS s[0].tsrbuffer, 1);
+#endif
+  }
+
+  BX_SER_THIS s[0].line_status.tsr_empty = 1;
+  if (BX_SER_THIS s[0].fifo_cntl.enable && (BX_SER_THIS s[0].tx_fifo_end > 0)) {
+    BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].tx_fifo[0];
+    BX_SER_THIS s[0].line_status.tsr_empty = 0;
+    memcpy(&BX_SER_THIS s[0].tx_fifo[0], &BX_SER_THIS s[0].tx_fifo[1], 15);
+    gen_int = (--BX_SER_THIS s[0].tx_fifo_end == 0);
+  } else if (!BX_SER_THIS s[0].line_status.thr_empty) {
+    BX_SER_THIS s[0].tsrbuffer = BX_SER_THIS s[0].thrbuffer;
+    BX_SER_THIS s[0].line_status.tsr_empty = 0;
+    gen_int = 1;
+  }
+  if (!BX_SER_THIS s[0].line_status.tsr_empty) {
+    if (gen_int) {
+      BX_SER_THIS s[0].line_status.thr_empty = 1;
+      raise_interrupt(0, BX_SER_INT_TXHOLD);
+    }
+    bx_pc_system.activate_timer(BX_SER_THIS s[0].tx_timer_index,
+                                (int) (1000000.0 / BX_SER_THIS s[0].baudrate *
+                                (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5)),
+                                0); /* not continuous */
+  }
+}
+
+
+void
+bx_serial_c::rx_timer_handler(void *this_ptr)
+{
+  bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+  class_ptr->rx_timer();
+}
+
+
+void
+bx_serial_c::rx_timer(void)
+{
+#if BX_HAVE_SELECT
+#ifndef __BEOS__
+  struct timeval tval;
+  fd_set fds;
+#endif
+#endif
+  int bdrate = BX_SER_THIS s[0].baudrate / (BX_SER_THIS s[0].line_cntl.wordlen_sel + 5);
+  unsigned char chbuf = 0;
+
+#if BX_HAVE_SELECT
+#ifndef __BEOS__
+  tval.tv_sec  = 0;
+  tval.tv_usec = 0;
+
+// MacOS: I'm not sure what to do with this, since I don't know
+// what an fd_set is or what FD_SET() or select() do. They aren't
+// declared in the CodeWarrior standard library headers. I'm just
+// leaving it commented out for the moment.
+
+  FD_ZERO(&fds);
+  if (tty_id >= 0) FD_SET(tty_id, &fds);
+
+  if ((BX_SER_THIS s[0].line_status.rxdata_ready == 0) ||
+      (BX_SER_THIS s[0].fifo_cntl.enable)) {
+#if USE_RAW_SERIAL
+    bx_bool rdy;
+    uint16 data;
+    if ((rdy = BX_SER_THIS raw->ready_receive())) {
+      data = BX_SER_THIS raw->receive();
+      if (data == C_BREAK) {
+           BX_DEBUG(("got BREAK"));
+           BX_SER_THIS s[0].line_status.break_int = 1;
+           rdy = 0;
+      }
+    }
+    if (rdy) {
+      chbuf = data;
+#elif defined(SERIAL_ENABLE)
+    if ((tty_id >= 0) && (select(tty_id + 1, &fds, NULL, NULL, &tval) == 1)) {
+      (void) read(tty_id, &chbuf, 1);
+      BX_DEBUG(("read: '%c'",chbuf));
+#else
+    if (0) {
+#endif
+      if (!BX_SER_THIS s[0].modem_cntl.local_loopback) {
+        rx_fifo_enq(0, chbuf);
+      }
+    } else {
+      if (!BX_SER_THIS s[0].fifo_cntl.enable) {
+        bdrate = (int) (1000000.0 / 100000); // Poll frequency is 100ms
+      }
+    }
+  } else {
+    // Poll at 4x baud rate to see if the next-char can
+    // be read
+    bdrate *= 4;
+  }
+#endif
+#endif
+
+  bx_pc_system.activate_timer(BX_SER_THIS s[0].rx_timer_index,
+                             (int) (1000000.0 / bdrate),
+                             0); /* not continuous */
+}
+
+
+void
+bx_serial_c::fifo_timer_handler(void *this_ptr)
+{
+  bx_serial_c *class_ptr = (bx_serial_c *) this_ptr;
+
+  class_ptr->fifo_timer();
+}
+
+
+void
+bx_serial_c::fifo_timer(void)
+{
+  BX_SER_THIS s[0].line_status.rxdata_ready = 1;
+  raise_interrupt(0, BX_SER_INT_FIFO);
+}
diff --git a/tools/ioemu/iodev/serial.h b/tools/ioemu/iodev/serial.h
new file mode 100644 (file)
index 0000000..00f01c9
--- /dev/null
@@ -0,0 +1,193 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial.h,v 1.15 2003/11/16 08:21:10 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Peter Grehan (grehan@iprg.nokia.com) coded most of this
+// serial emulation.
+
+#if USE_RAW_SERIAL
+#include "serial_raw.h"
+#endif // USE_RAW_SERIAL
+
+#if BX_USE_SER_SMF
+#  define BX_SER_SMF  static
+#  define BX_SER_THIS theSerialDevice->
+#else
+#  define BX_SER_SMF
+#  define BX_SER_THIS this->
+#endif
+
+#define BX_SERIAL_MAXDEV   4
+
+#define  BX_PC_CLOCK_XTL   1843200.0
+
+#define  BX_SER_RXIDLE  0
+#define  BX_SER_RXPOLL  1
+#define  BX_SER_RXWAIT  2
+
+enum {
+  BX_SER_INT_IER,
+  BX_SER_INT_RXDATA,
+  BX_SER_INT_TXHOLD,
+  BX_SER_INT_RXLSTAT,
+  BX_SER_INT_MODSTAT,
+  BX_SER_INT_FIFO
+};
+
+typedef struct {
+  /*
+   * UART internal state
+   */
+  bx_bool  ls_interrupt;
+  bx_bool  ms_interrupt;
+  bx_bool  rx_interrupt;
+  bx_bool  tx_interrupt;
+  bx_bool  fifo_interrupt;
+  bx_bool  ls_ipending;
+  bx_bool  ms_ipending;
+  bx_bool  rx_ipending;
+  bx_bool  fifo_ipending;
+
+  Bit8u IRQ;
+
+  Bit8u rx_fifo_end;
+  Bit8u tx_fifo_end;
+
+  int  baudrate;
+  int  tx_timer_index;
+
+  int  rx_pollstate;
+  int  rx_timer_index;
+  int  fifo_timer_index;
+
+  /*
+   * Register definitions
+   */
+  Bit8u     rxbuffer;     /* receiver buffer register (r/o) */
+  Bit8u     thrbuffer;    /* transmit holding register (w/o) */
+  /* Interrupt Enable Register */
+  struct {
+    bx_bool    rxdata_enable;      /* 1=enable receive data interrupts */
+    bx_bool    txhold_enable;      /* 1=enable tx. holding reg. empty ints */
+    bx_bool    rxlstat_enable;     /* 1=enable rx line status interrupts */
+    bx_bool    modstat_enable;     /* 1=enable modem status interrupts */
+  } int_enable;
+  /* Interrupt Identification Register (r/o) */
+  struct {
+    bx_bool    ipending;           /* 0=interrupt pending */
+    Bit8u      int_ID;             /* 3-bit interrupt ID */
+  } int_ident;
+  /* FIFO Control Register (w/o) */
+  struct {
+    bx_bool    enable;             /* 1=enable tx and rx FIFOs */
+    Bit8u      rxtrigger;          /* 2-bit code for rx fifo trigger level */
+  } fifo_cntl;
+  /* Line Control Register (r/w) */
+  struct {
+    Bit8u      wordlen_sel;        /* 2-bit code for char length */
+    bx_bool    stopbits;           /* select stop bit len */
+    bx_bool    parity_enable;      /* ... */
+    bx_bool    evenparity_sel;     /* ... */
+    bx_bool    stick_parity;       /* ... */
+    bx_bool    break_cntl;         /* 1=send break signal */
+    bx_bool    dlab;               /* divisor latch access bit */
+  } line_cntl;
+  /* MODEM Control Register (r/w) */
+  struct {
+    bx_bool    dtr;                /* DTR output value */
+    bx_bool    rts;                /* RTS output value */
+    bx_bool    out1;               /* OUTPUT1 value */
+    bx_bool    out2;               /* OUTPUT2 value */
+    bx_bool    local_loopback;     /* 1=loopback mode */
+  } modem_cntl;
+  /* Line Status Register (r/w) */
+  struct {
+    bx_bool    rxdata_ready;       /* 1=receiver data ready */
+    bx_bool    overrun_error;      /* 1=receive overrun detected */
+    bx_bool    parity_error;       /* 1=rx char has a bad parity bit */
+    bx_bool    framing_error;      /* 1=no stop bit detected for rx char */
+    bx_bool    break_int;          /* 1=break signal detected */
+    bx_bool    thr_empty;          /* 1=tx hold register (or fifo) is empty */
+    bx_bool    tsr_empty;          /* 1=shift reg and hold reg empty */
+    bx_bool    fifo_error;         /* 1=at least 1 err condition in fifo */
+  } line_status;
+  /* Modem Status Register (r/w) */
+  struct {
+    bx_bool    delta_cts;          /* 1=CTS changed since last read */
+    bx_bool    delta_dsr;          /* 1=DSR changed since last read */
+    bx_bool    ri_trailedge;       /* 1=RI moved from low->high */
+    bx_bool    delta_dcd;          /* 1=CD changed since last read */
+    bx_bool    cts;                /* CTS input value */
+    bx_bool    dsr;                /* DSR input value */
+    bx_bool    ri;                 /* RI input value */
+    bx_bool    dcd;                /* DCD input value */
+  } modem_status;
+
+  Bit8u  scratch;       /* Scratch Register (r/w) */
+  Bit8u  tsrbuffer;     /* transmit shift register (internal) */
+  Bit8u  rx_fifo[16];   /* receive FIFO (internal) */
+  Bit8u  tx_fifo[16];   /* transmit FIFO (internal) */
+  Bit8u  divisor_lsb;   /* Divisor latch, least-sig. byte */
+  Bit8u  divisor_msb;   /* Divisor latch, most-sig. byte */
+} bx_serial_t;
+
+
+
+class bx_serial_c : public bx_devmodel_c {
+public:
+  bx_serial_c(void);
+  ~bx_serial_c(void);
+  virtual void   init(void);
+  virtual void   reset(unsigned type);
+#if USE_RAW_SERIAL
+  serial_raw* raw;
+#endif // USE_RAW_SERIAL
+
+private:
+    bx_serial_t s[BX_SERIAL_MAXDEV];
+
+  static void lower_interrupt(Bit8u port);
+  static void raise_interrupt(Bit8u port, int type);
+
+  static void rx_fifo_enq(Bit8u port, Bit8u data);
+
+  static void tx_timer_handler(void *);
+  BX_SER_SMF void tx_timer(void);
+
+  static void rx_timer_handler(void *);
+  BX_SER_SMF void rx_timer(void);
+
+  static void fifo_timer_handler(void *);
+  BX_SER_SMF void fifo_timer(void);
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_SER_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+  };
+
diff --git a/tools/ioemu/iodev/serial_raw.h b/tools/ioemu/iodev/serial_raw.h
new file mode 100644 (file)
index 0000000..978c28d
--- /dev/null
@@ -0,0 +1,23 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: serial_raw.h,v 1.2 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+#include <linux/serial.h>
+
+#define P_EVEN 0
+#define P_ODD 1
+#define C_BREAK 201
+
+class serial_raw : public logfunctions {
+  public:
+    serial_raw (char *ttypath, int signal);
+    void set_baudrate (int rate);
+    void set_data_bits (int );
+    void set_stop_bits (int);
+    void set_parity_mode (int, int);
+    void transmit (int byte);
+    void send_hangup ();
+    int ready_transmit ();
+    int ready_receive ();
+    int receive ();
+};
diff --git a/tools/ioemu/iodev/slowdown_timer.cc b/tools/ioemu/iodev/slowdown_timer.cc
new file mode 100644 (file)
index 0000000..76d8613
--- /dev/null
@@ -0,0 +1,182 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: slowdown_timer.cc,v 1.17.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+
+#include "bochs.h"
+#include <errno.h>
+
+//These need to stay printfs because they are useless in the log file.
+#define BX_SLOWDOWN_PRINTF_FEEDBACK 0
+
+#define SECINUSEC 1000000
+#define usectosec(a) ((a)/SECINUSEC)
+#define sectousec(a) ((a)*SECINUSEC)
+#define nsectousec(a) ((a)/1000)
+
+#define MSECINUSEC 1000
+#define usectomsec(a) ((a)/MSECINUSEC)
+
+#if BX_HAVE_USLEEP
+#  define Qval 1000
+#else
+#  define Qval SECINUSEC
+#endif
+
+#define MAXMULT 1.5
+#define REALTIME_Q SECINUSEC
+
+#define LOG_THIS bx_slowdown_timer.
+
+bx_slowdown_timer_c bx_slowdown_timer;
+
+bx_slowdown_timer_c::bx_slowdown_timer_c() {
+  put("STIMER");
+  settype(STIMERLOG);
+
+
+  s.start_time=0;
+  s.start_emulated_time=0;
+  s.timer_handle=BX_NULL_TIMER_HANDLE;
+}
+
+void
+bx_slowdown_timer_c::init(void) {
+
+  // Return early if slowdown timer not selected
+  if ( (bx_options.clock.Osync->get () != BX_CLOCK_SYNC_SLOWDOWN)
+    && (bx_options.clock.Osync->get () != BX_CLOCK_SYNC_BOTH) )
+    return;
+
+  BX_INFO(("using 'slowdown' timer synchronization method"));
+  s.MAXmultiplier=MAXMULT;
+  s.Q=Qval;
+
+  if(s.MAXmultiplier<1)
+    s.MAXmultiplier=1;
+
+  s.start_time=sectousec(time(NULL));
+  s.start_emulated_time = bx_pc_system.time_usec();
+  s.lasttime=0;
+  if (s.timer_handle == BX_NULL_TIMER_HANDLE) {
+    s.timer_handle=bx_pc_system.register_timer(this, timer_handler, 100 , 1, 1,
+       "slowdown_timer");
+  }
+  bx_pc_system.deactivate_timer(s.timer_handle);
+  bx_pc_system.activate_timer(s.timer_handle,(Bit32u)s.Q,0);
+}
+
+void
+bx_slowdown_timer_c::reset(unsigned type)
+{
+}
+
+void
+bx_slowdown_timer_c::timer_handler(void * this_ptr) {
+  bx_slowdown_timer_c * class_ptr = (bx_slowdown_timer_c *) this_ptr;
+
+  class_ptr->handle_timer();
+}
+
+void
+bx_slowdown_timer_c::handle_timer() {
+  Bit64u total_emu_time = (bx_pc_system.time_usec()) - s.start_emulated_time;
+  Bit64u wanttime = s.lasttime+s.Q;
+  Bit64u totaltime = sectousec(time(NULL)) - s.start_time;
+  Bit64u thistime=(wanttime>totaltime)?wanttime:totaltime;
+
+#if BX_SLOWDOWN_PRINTF_FEEDBACK
+  printf("Entering slowdown timer handler.\n");
+#endif
+
+  /* Decide if we're behind.
+   * Set interrupt interval accordingly. */
+  if(totaltime > total_emu_time) {
+    bx_pc_system.deactivate_timer(s.timer_handle);
+    bx_pc_system.activate_timer(s.timer_handle,
+                               (Bit32u)(s.MAXmultiplier * (float)((Bit64s)s.Q)),
+                               0);
+#if BX_SLOWDOWN_PRINTF_FEEDBACK
+    printf("running at MAX speed\n");
+#endif
+  } else {
+    bx_pc_system.deactivate_timer(s.timer_handle);
+    bx_pc_system.activate_timer(s.timer_handle,s.Q,0);
+#if BX_SLOWDOWN_PRINTF_FEEDBACK
+    printf("running at NORMAL speed\n");
+#endif
+  }
+
+  /* Make sure we took at least one time quantum. */
+  /* This is a little strange.  I'll try to explain.
+   * We're running bochs one second ahead of real time.
+   *  this gives us a very precise division on whether
+   *  we're ahead or behind the second line.
+   * Basically, here's how it works:
+   * *****|******************|***********...
+   *      Time               Time+1sec
+   *                        <^Bochs doesn't delay.
+   *                          ^>Bochs delays.
+   *    <^Bochs runs at MAX speed.
+   *      ^>Bochs runs at normal
+   */
+  if(wanttime > (totaltime+REALTIME_Q)) {
+#if BX_HAVE_USLEEP
+    usleep(s.Q);
+#elif BX_HAVE_MSLEEP
+    msleep(usectomsec(s.Q));
+#elif BX_HAVE_SLEEP
+    sleep(usectosec(s.Q));
+#else
+#error do not know have to sleep
+#endif    //delay(wanttime-totaltime);
+    /*alternatively: delay(Q);
+     * This works okay because we share the delay between
+     * two time quantums.
+     */
+#if BX_SLOWDOWN_PRINTF_FEEDBACK
+    printf("DELAYING for a quantum\n");
+#endif
+  }
+  s.lasttime=thistime;
+
+  //Diagnostic info:
+#if 0
+  if(wanttime > (totaltime+REALTIME_Q)) {
+    if(totaltime > total_emu_time) {
+      printf("Solving OpenBSD problem.\n");
+    } else {
+      printf("too fast.\n");
+    }
+  } else {
+    if(totaltime > total_emu_time) {
+      printf("too slow.\n");
+    } else {
+      printf("sometimes invalid state, normally okay.\n");
+    }
+  }
+#endif // Diagnostic info
+}
+
diff --git a/tools/ioemu/iodev/slowdown_timer.h b/tools/ioemu/iodev/slowdown_timer.h
new file mode 100644 (file)
index 0000000..3b6b153
--- /dev/null
@@ -0,0 +1,33 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: slowdown_timer.h,v 1.8 2003/08/19 00:10:38 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+
+class bx_slowdown_timer_c : public logfunctions {
+
+private:
+  struct {
+    Bit64u start_time;
+    Bit64u start_emulated_time;
+    Bit64u lasttime;
+
+    int timer_handle;
+
+    float MAXmultiplier;
+    Bit64u Q; // (Q (in seconds))
+  } s;
+
+public:
+  bx_slowdown_timer_c();
+
+  void init(void);
+  void reset(unsigned type);
+
+  static void timer_handler(void * this_ptr);
+
+  void handle_timer();
+
+};
+
+extern bx_slowdown_timer_c bx_slowdown_timer;
+
diff --git a/tools/ioemu/iodev/soundlnx.cc b/tools/ioemu/iodev/soundlnx.cc
new file mode 100644 (file)
index 0000000..773addc
--- /dev/null
@@ -0,0 +1,227 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundlnx.cc,v 1.6 2002/12/24 10:12:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// This file (SOUNDLNX.CC) written and donated by Josef Drexler
+
+
+#include "bochs.h"
+#if (defined(linux) || defined(__FreeBSD__)) && BX_SUPPORT_SB16
+#define LOG_THIS bx_sb16.
+
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+bx_sound_linux_c::bx_sound_linux_c(bx_sb16_c *sb16)
+  :bx_sound_output_c(sb16)
+{
+  this->sb16 = sb16;
+  midi = NULL;
+  wavedevice = NULL;
+  wave = -1;
+}
+
+bx_sound_linux_c::~bx_sound_linux_c()
+{
+  // nothing for now
+}
+
+
+int bx_sound_linux_c::waveready()
+{
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::midiready()
+{
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::openmidioutput(char *device)
+{
+  if ( (device == NULL) || (strlen(device) < 1) )
+    return BX_SOUND_OUTPUT_ERR;
+
+  midi = fopen(device,"w");
+
+  if (midi == NULL)
+    {
+      WRITELOG( MIDILOG(2), "Couldn't open midi output device %s: %s.",
+               device, strerror(errno));
+      return BX_SOUND_OUTPUT_ERR;
+    }
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+
+int bx_sound_linux_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
+{
+  UNUSED(delta);
+  //  BX_PANIC(("Sendmidicommand!!");
+
+  fputc(command, midi);
+  fwrite(data, 1, length, midi);
+  fflush(midi);       // to start playing immediately
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+
+int bx_sound_linux_c::closemidioutput()
+{
+  fclose(midi);
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+
+int bx_sound_linux_c::openwaveoutput(char *device)
+{
+  int length = strlen(device) + 1;
+
+  if (wavedevice != NULL)
+    delete(wavedevice);
+
+  wavedevice = new char[length];
+
+  if (wavedevice == NULL)
+    return BX_SOUND_OUTPUT_ERR;
+
+  strncpy(wavedevice, device, length);
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::startwaveplayback(int frequency, int bits, int stereo, int format)
+{
+  int fmt, ret;
+  int signeddata = format & 1;
+
+  if ( (wavedevice == NULL) || (strlen(wavedevice) < 1) )
+    return BX_SOUND_OUTPUT_ERR;
+
+  if (wave == -1)
+    wave = open(wavedevice, O_WRONLY);
+  else
+    if ( (frequency == oldfreq) &&
+        (bits == oldbits) &&
+        (stereo == oldstereo) &&
+        (format == oldformat) )
+      return BX_SOUND_OUTPUT_OK;    // nothing to do
+
+  oldfreq = frequency;
+  oldbits = bits;
+  oldstereo = stereo;
+  oldformat = format;
+
+  if (wave == -1)
+    return BX_SOUND_OUTPUT_ERR;
+
+  if (bits == 16)
+    if (signeddata == 1)
+      fmt = AFMT_S16_LE;
+    else
+      fmt = AFMT_U16_LE;
+  else if (bits == 8)
+    if (signeddata == 1)
+      fmt = AFMT_S8;
+    else
+      fmt = AFMT_U8;
+  else
+    return BX_SOUND_OUTPUT_ERR;
+      // set frequency etc.
+  ret = ioctl(wave, SNDCTL_DSP_RESET);
+  if (ret != 0)
+    WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_RESET): %s", strerror(errno));
+
+  /*
+  ret = ioctl(wave, SNDCTL_DSP_SETFRAGMENT, &fragment);
+  if (ret != 0)
+    WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_SETFRAGMENT, %d): %s",
+             fragment, strerror(errno));
+  */
+
+  ret = ioctl(wave, SNDCTL_DSP_SETFMT, &fmt);
+  if (ret != 0)   // abort if the format is unknown, to avoid playing noise
+    {
+      WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_SETFMT, %d): %s",
+               fmt, strerror(errno));
+      return BX_SOUND_OUTPUT_ERR;
+    }
+
+  ret = ioctl(wave, SNDCTL_DSP_STEREO, &stereo);
+  if (ret != 0)
+    WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_STEREO, %d): %s", 
+             stereo, strerror(errno));
+
+  ret = ioctl(wave, SNDCTL_DSP_SPEED, &frequency);
+  if (ret != 0)
+    WRITELOG( WAVELOG(4), "ioctl(SNDCTL_DSP_SPEED, %d): %s", 
+             frequency, strerror(errno));
+
+  //  ioctl(wave, SNDCTL_DSP_GETBLKSIZE, &fragment);
+  //  WRITELOG( WAVELOG(4), "current output block size is %d", fragment);
+
+  return BX_SOUND_OUTPUT_OK;
+}
+                        
+int bx_sound_linux_c::sendwavepacket(int length, Bit8u data[])
+{
+  int ret;
+
+  ret = write(wave, data, length);
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::stopwaveplayback()
+{
+  //  ioctl(wave, SNDCTL_DSP_SYNC);
+  //  close(wave);
+  //  wave = -1;
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_linux_c::closewaveoutput()
+{
+  if (wavedevice != NULL)
+    delete(wavedevice);
+
+  if (wave != -1)
+    {
+      close(wave);
+      wave = -1;
+    }
+
+  wavedevice = NULL;
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+#endif  // defined(linux)
diff --git a/tools/ioemu/iodev/soundlnx.h b/tools/ioemu/iodev/soundlnx.h
new file mode 100644 (file)
index 0000000..8f718b5
--- /dev/null
@@ -0,0 +1,69 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundlnx.h,v 1.5 2002/12/24 10:12:26 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// This file (SOUNDLNX.H) written and donated by Josef Drexler
+
+
+#if (defined(linux) || defined(__FreeBSD__))
+
+#include "bochs.h"
+
+#define BX_SOUND_LINUX_BUFSIZE   BX_SOUND_OUTPUT_WAVEPACKETSIZE
+
+class bx_sound_linux_c : public bx_sound_output_c {
+public:
+  bx_sound_linux_c(bx_sb16_c *sb16);
+  BX_SOUND_VIRTUAL ~bx_sound_linux_c();
+
+  // if virtual functions are used, we have to override them
+  // and define our own. Otherwise this file will just implement
+  // the original functions
+#ifdef BX_USE_SOUND_VIRTUAL
+  BX_SOUND_VIRTUAL int    waveready();
+  BX_SOUND_VIRTUAL int    midiready();
+
+  BX_SOUND_VIRTUAL int    openmidioutput(char *device);
+  BX_SOUND_VIRTUAL int    sendmidicommand(int delta, int command, int length, Bit8u data[]);
+  BX_SOUND_VIRTUAL int    closemidioutput();
+
+  BX_SOUND_VIRTUAL int    openwaveoutput(char *device);
+  BX_SOUND_VIRTUAL int    startwaveplayback(int frequency, int bits, int stereo, int format);
+  BX_SOUND_VIRTUAL int    sendwavepacket(int length, Bit8u data[]);
+  BX_SOUND_VIRTUAL int    stopwaveplayback();
+  BX_SOUND_VIRTUAL int    closewaveoutput();
+#endif
+
+private:
+  bx_sb16_c *sb16;
+  FILE *midi;
+  char *wavedevice;
+  int wave;
+  int bufferpos;
+  Bit8u audio_buffer[BX_SOUND_LINUX_BUFSIZE];
+  int oldfreq,oldbits,oldstereo,oldformat;
+};
+
+#endif  // defined(linux)
diff --git a/tools/ioemu/iodev/soundwin.cc b/tools/ioemu/iodev/soundwin.cc
new file mode 100644 (file)
index 0000000..b8b386c
--- /dev/null
@@ -0,0 +1,521 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundwin.cc,v 1.13 2003/04/05 08:26:49 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// This file (SOUNDWIN.CC) written and donated by Josef Drexler
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+#if defined(WIN32) && BX_SUPPORT_SB16
+
+#define LOG_THIS bx_devices.pluginSB16Device->
+
+bx_sound_windows_c::bx_sound_windows_c(bx_sb16_c *sb16)
+  :bx_sound_output_c(sb16)
+{
+  this->sb16 = sb16;
+
+  MidiOpen = 0;
+  WaveOpen = 0;
+
+  ismidiready = 1;
+  iswaveready = 1;
+
+  // size is the total size of the midi header and buffer and the
+  // BX_SOUND_WINDOWS_NBUF wave header and buffers, all aligned
+  // on a 16-byte boundary
+
+#define ALIGN(size) ( (size + 15) & ~15 )
+
+#define size   ALIGN(sizeof(MIDIHDR)) \
+            + ALIGN(sizeof(WAVEHDR)) \
+            + ALIGN(BX_SOUND_WINDOWS_MAXSYSEXLEN) * BX_SOUND_WINDOWS_NBUF \
+            + ALIGN(BX_SOUND_OUTPUT_WAVEPACKETSIZE) * BX_SOUND_WINDOWS_NBUF
+
+  DataHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
+  DataPointer = (Bit8u*) GlobalLock(DataHandle);
+
+  if (DataPointer == NULL)
+    BX_PANIC(("GlobalLock returned NULL-pointer"));
+
+#define NEWBUFFER(size) &(DataPointer[offset]); offset += ALIGN(size)
+
+  int offset = 0;
+  MidiHeader = (LPMIDIHDR) NEWBUFFER(sizeof(MIDIHDR));
+  MidiData = (LPSTR) NEWBUFFER(BX_SOUND_WINDOWS_MAXSYSEXLEN);
+
+  for (int bufnum=0; bufnum<BX_SOUND_WINDOWS_NBUF; bufnum++)
+    {
+      WaveHeader[bufnum] = (LPWAVEHDR) NEWBUFFER(sizeof(WAVEHDR));
+      WaveData[bufnum] = (LPSTR) NEWBUFFER(BX_SOUND_OUTPUT_WAVEPACKETSIZE);
+    }
+
+  if (offset > size)
+    BX_PANIC(("Allocated memory was too small!"));
+
+#undef size
+#undef ALIGN
+#undef NEWBUFFER
+}
+
+bx_sound_windows_c::~bx_sound_windows_c()
+{
+  GlobalUnlock(DataHandle);
+  GlobalFree(DataHandle);
+}
+
+int bx_sound_windows_c::waveready()
+{
+  if (iswaveready == 0)
+    checkwaveready();
+
+  if (iswaveready == 1)
+    return BX_SOUND_OUTPUT_OK;
+  else
+    return BX_SOUND_OUTPUT_ERR;
+}
+int bx_sound_windows_c::midiready()
+{
+  if (ismidiready == 0)
+    checkmidiready();
+
+  if (ismidiready == 1)
+    return BX_SOUND_OUTPUT_OK;
+  else
+    return BX_SOUND_OUTPUT_ERR;
+}
+
+int bx_sound_windows_c::openmidioutput(char *device)
+{
+  // could make the output device selectable,
+  // but currently only the midi mapper is supported
+  UNUSED(device);
+
+  UINT deviceid = (UINT) MIDIMAPPER;
+
+  MidiOpen = 0;
+
+  UINT ret = midiOutOpen( &MidiOut, deviceid, 0, 0, CALLBACK_NULL);
+  if (ret == 0)
+    MidiOpen = 1;
+
+  WRITELOG( MIDILOG(4), "midiOutOpen() = %d, MidiOpen: %d", ret, MidiOpen);
+
+  return (MidiOpen == 1) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
+}
+
+int bx_sound_windows_c::sendmidicommand(int delta, int command, int length, Bit8u data[])
+{
+  UINT ret;
+
+  if (MidiOpen != 1)
+    return BX_SOUND_OUTPUT_ERR;
+
+  if ( (command == 0xf0) || (command == 0xf7) || (length > 3) )
+    {
+      WRITELOG( WAVELOG(5), "SYSEX started, length %d", length);
+      ismidiready = 0;   // until the buffer is done
+      memcpy(MidiData, data, length);
+      MidiHeader->lpData = MidiData;
+      MidiHeader->dwBufferLength = BX_SOUND_WINDOWS_MAXSYSEXLEN;
+      MidiHeader->dwBytesRecorded = 0;
+      MidiHeader->dwUser = 0;
+      MidiHeader->dwFlags = 0;
+      ret = midiOutPrepareHeader(MidiOut, MidiHeader, sizeof(*MidiHeader));
+      if (ret != 0)
+       WRITELOG( MIDILOG(2), "midiOutPrepareHeader() = %d", ret);
+      ret = midiOutLongMsg(MidiOut, MidiHeader, sizeof(*MidiHeader));
+      if (ret != 0)
+       WRITELOG( MIDILOG(2), "midiOutLongMsg() = %d", ret);
+    }
+  else
+    {
+      DWORD msg = command;
+
+      for (int i = 0; i<length; i++)
+       msg |= (data[i] << (8 * (i + 1) ) );
+
+      ret = midiOutShortMsg(MidiOut, msg);
+      WRITELOG( MIDILOG(4), "midiOutShortMsg(%x) = %d", msg, ret);
+    }
+
+  return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
+}
+
+int bx_sound_windows_c::closemidioutput()
+{
+  UINT ret;
+
+  if (MidiOpen != 1)
+    return BX_SOUND_OUTPUT_ERR;
+
+  ret = midiOutReset(MidiOut);
+  if (ismidiready == 0)
+    checkmidiready();   // to clear any pending SYSEX
+
+  ret = midiOutClose(MidiOut);
+  WRITELOG( MIDILOG(4), "midiOutClose() = %d", ret);
+  MidiOpen = 0;
+
+  return (ret == 0) ? BX_SOUND_OUTPUT_OK : BX_SOUND_OUTPUT_ERR;
+}
+
+int bx_sound_windows_c::openwaveoutput(char *device)
+{
+  // could make the output device selectable,
+  // but currently only the midi mapper is supported
+  UNUSED(device);
+
+  WRITELOG( WAVELOG(4), "openwaveoutput(%s)", device);
+
+#ifdef usewaveOut
+  WaveDevice = (UINT) WAVEMAPPER;
+
+  for (int i=0; i<BX_SOUND_WINDOWS_NBUF; i++)
+    WaveHeader[i]->dwFlags = WHDR_DONE;
+
+  head = 0;
+  tailfull = 0;
+  tailplay = 0;
+  needreopen = 0;
+#endif
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::playnextbuffer()
+{
+  UINT ret;
+  PCMWAVEFORMAT waveformat;
+  int bufnum;
+
+  // if the format is different, we have to reopen the device,
+  // so reset it first
+  if (needreopen != 0)
+    if (WaveOpen != 0)
+      ret = waveOutReset( WaveOut );
+
+  // clean up the buffers and mark if output is ready
+  checkwaveready();
+
+  // do we have to play anything?
+  if (tailplay == head)
+    return BX_SOUND_OUTPUT_OK;
+
+  // if the format is different, we have to close and reopen the device
+  // or, just open the device if it's not open yet
+  if ( (needreopen != 0) || (WaveOpen == 0) )
+    {
+      if (WaveOpen != 0)
+       {
+         ret = waveOutClose( WaveOut );
+         WaveOpen = 0;
+       }
+
+      // try three times to find a suitable format
+      for (int tries = 0; tries < 3; tries++)
+       {
+         int frequency = WaveInfo.frequency;
+         int stereo = WaveInfo.stereo;
+         int bits = WaveInfo.bits;
+         int format = WaveInfo.format;
+         int bps = (bits / 8) * (stereo + 1);
+
+         waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
+         waveformat.wf.nChannels = stereo + 1;
+         waveformat.wf.nSamplesPerSec = frequency;
+         waveformat.wf.nAvgBytesPerSec = frequency * bps;
+         waveformat.wf.nBlockAlign = bps;
+         waveformat.wBitsPerSample = bits;
+
+         ret = waveOutOpen( &(WaveOut), WaveDevice, (LPWAVEFORMATEX)&(waveformat.wf), 0, 0, CALLBACK_NULL);
+         if (ret != 0)
+           {
+             char errormsg[4*MAXERRORLENGTH+1];
+             waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
+             WRITELOG( WAVELOG(5), "waveOutOpen: %s", errormsg);
+             switch (tries)
+               {
+               case 0: // maybe try a different frequency
+                 if (frequency < 15600)
+                   frequency = 11025;
+                 else if (frequency < 31200)
+                   frequency = 22050;
+                 else
+                   frequency = 44100;
+
+                 WRITELOG( WAVELOG(4), "Couldn't open wave device (error %d), trying frequency %d", ret, frequency);
+
+                 break;
+               case 1: // or something else
+                 frequency = 11025;
+                 stereo = 0;
+                 bits = 8;
+                 bps = 1;
+
+                 WRITELOG( WAVELOG(4), "Couldn't open wave device again (error %d), trying 11KHz, mono, 8bit", ret);
+
+                 break;
+               case 2: // nope, doesn't work
+
+                 WRITELOG( WAVELOG(2), "Couldn't open wave device (error %d)!", ret);
+
+                 return BX_SOUND_OUTPUT_ERR;
+               }
+             WRITELOG( WAVELOG(5), "The format was: wFormatTag=%d, nChannels=%d, nSamplesPerSec=%d,",
+                       waveformat.wf.wFormatTag, waveformat.wf.nChannels, waveformat.wf.nSamplesPerSec);
+             WRITELOG( WAVELOG(5), "                nAvgBytesPerSec=%d, nBlockAlign=%d, wBitsPerSample=%d",
+                       waveformat.wf.nAvgBytesPerSec, waveformat.wf.nBlockAlign, waveformat.wBitsPerSample);
+
+           }
+         else
+           {
+             WaveOpen = 1;
+             needreopen = 0;
+             break;
+           }
+       }
+    }
+
+  for (bufnum=tailplay; bufnum != head;
+       bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK, tailplay=bufnum)
+    {
+      WRITELOG( WAVELOG(5), "Playing buffer %d", bufnum);
+
+      // prepare the wave header
+      WaveHeader[bufnum]->lpData = WaveData[bufnum];
+      WaveHeader[bufnum]->dwBufferLength = length[bufnum];
+      WaveHeader[bufnum]->dwBytesRecorded = length[bufnum];
+      WaveHeader[bufnum]->dwUser = 0;
+      WaveHeader[bufnum]->dwFlags = 0;
+      WaveHeader[bufnum]->dwLoops = 1;
+
+      ret = waveOutPrepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
+      if (ret != 0)
+       {
+         WRITELOG( WAVELOG(2), "waveOutPrepareHeader = %d", ret);
+         return BX_SOUND_OUTPUT_ERR;
+       }
+
+      ret = waveOutWrite(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
+      if (ret != 0)
+       {
+         char errormsg[4*MAXERRORLENGTH+1];
+         waveOutGetErrorTextA(ret, errormsg, 4*MAXERRORLENGTH+1);
+         WRITELOG( WAVELOG(5), "waveOutWrite: %s", errormsg);
+       }
+    }
+    return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::startwaveplayback(int frequency, int bits, int stereo, int format)
+{
+  // UINT ret;
+
+  WRITELOG( WAVELOG(4), "startwaveplayback(%d, %d, %d, %x)", frequency, bits, stereo, format);
+
+#ifdef usewaveOut
+  // check if any of the properties have changed
+  if ( (WaveInfo.frequency != frequency) ||
+       (WaveInfo.bits != bits) ||
+       (WaveInfo.stereo != stereo) ||
+       (WaveInfo.format != format) )
+    {
+      needreopen = 1;
+
+      // store the current settings to be used by sendwavepacket()
+      WaveInfo.frequency = frequency;
+      WaveInfo.bits = bits;
+      WaveInfo.stereo = stereo;
+      WaveInfo.format = format;
+    }
+#endif
+
+#ifdef usesndPlaySnd
+  int bps = (bits / 8) * (stereo + 1);
+  LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData;
+
+  memcpy(header->RIFF, "RIFF", 4);
+  memcpy(header->TYPE, "WAVE", 4);
+  memcpy(header->chnk, "fmt ", 4);
+  header->chnklen = 16;
+  header->waveformat.wf.wFormatTag = WAVE_FORMAT_PCM;
+  header->waveformat.wf.nChannels = stereo + 1;
+  header->waveformat.wf.nSamplesPerSec = frequency;
+  header->waveformat.wf.nAvgBytesPerSec = frequency * bps;
+  header->waveformat.wf.nBlockAlign = bps;
+  header->waveformat.wBitsPerSample = bits;
+  memcpy(header->chnk2, "data", 4);
+#endif
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::sendwavepacket(int length, Bit8u data[])
+{
+//  UINT ret;
+  int bufnum;
+
+  WRITELOG( WAVELOG(4), "sendwavepacket(%d, %p)", length, data);
+
+#ifdef usewaveOut
+  bufnum = head;
+
+  memcpy(WaveData[bufnum], data, length);
+  this->length[bufnum] = length;
+
+  // select next buffer to write to
+  bufnum++;
+  bufnum &= BX_SOUND_WINDOWS_NMASK;
+
+  if ( ( (bufnum + 1) & BX_SOUND_WINDOWS_NMASK) == tailfull )
+    {   // this should not actually happen!
+      WRITELOG( WAVELOG(2), "Output buffer overflow! Not played. Iswaveready was %d", iswaveready);
+      iswaveready = 0;          // stop the output for a while
+      return BX_SOUND_OUTPUT_ERR;
+    }
+
+  head = bufnum;
+
+  // check if more buffers are available, otherwise stall the emulator
+  if ( ( (bufnum + 2) & BX_SOUND_WINDOWS_NMASK) == tailfull )
+    {
+      WRITELOG( WAVELOG(5), "Buffer status: Head %d, TailFull %d, TailPlay %d. Stall.",
+               head, tailfull, tailplay);
+      iswaveready = 0;
+    }
+
+  playnextbuffer();
+
+#endif
+
+#ifdef usesndPlaySnd
+  LPWAVEFILEHEADER header = (LPWAVEFILEHEADER) WaveData;
+
+  header->length = length + 36;
+  header->chnk2len = length;
+
+  memcpy( &(header->data), data, length);
+
+  FILE *test = fopen("test", "a");
+  fwrite(WaveData, 1, length + 44, test);
+  fclose(test);
+
+  ret = sndPlaySoundA( (LPCSTR) header, SND_SYNC | SND_MEMORY );
+  if (ret != 0)
+    {
+      WRITELOG( WAVELOG(3), "sndPlaySoundA: %d", ret);
+    }
+#endif
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::stopwaveplayback()
+{
+  WRITELOG( WAVELOG(4), "stopwaveplayback()");
+
+#ifdef usewaveOut
+  // this is handled by checkwaveready() when closing
+#endif
+
+#ifdef usesndPlaySnd
+  sndPlaySoundA( NULL, SND_ASYNC | SND_MEMORY );
+
+  WaveOpen = 0;
+#endif
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+int bx_sound_windows_c::closewaveoutput()
+{
+//  int bufnum;
+
+  WRITELOG( WAVELOG(4), "closewaveoutput");
+
+#ifdef usewaveOut
+  if (WaveOpen == 1)
+    {
+      waveOutReset(WaveOut);
+
+      // let checkwaveready() clean up the buffers
+      checkwaveready();
+
+      waveOutClose(WaveOut);
+
+      head = 0;
+      tailfull = 0;
+      tailplay = 0;
+      needreopen = 0;
+    }
+#endif
+
+  return BX_SOUND_OUTPUT_OK;
+}
+
+void bx_sound_windows_c::checkmidiready()
+{
+  UINT ret;
+
+  if ( (MidiHeader->dwFlags & WHDR_DONE) != 0)
+    {
+      WRITELOG( MIDILOG(5), "SYSEX message done, midi ready again.");
+      ret = midiOutUnprepareHeader( MidiOut, MidiHeader, sizeof(*MidiHeader));
+      ismidiready = 1;
+    }
+}
+void bx_sound_windows_c::checkwaveready()
+{
+  int bufnum;
+  UINT ret;
+
+  // clean up all finished buffers and mark them as available
+  for (bufnum=tailfull;
+       (bufnum != tailplay) &&
+         ( (WaveHeader[bufnum]->dwFlags & WHDR_DONE) != 0);
+       bufnum++, bufnum &= BX_SOUND_WINDOWS_NMASK)
+    {
+      WRITELOG( WAVELOG(5), "Buffer %d done.", bufnum);
+
+      ret = waveOutUnprepareHeader(WaveOut, WaveHeader[bufnum], sizeof(*WaveHeader[bufnum]));
+    }
+
+  tailfull = bufnum;
+
+  // enable gathering data if a buffer is available
+  if ( ( (head + 2) & BX_SOUND_WINDOWS_NMASK) != tailfull )
+    {
+      WRITELOG( WAVELOG(5), "Buffer status: Head %d, TailFull %d, TailPlay %d. Ready.",
+               head, tailfull, tailplay);
+      iswaveready = 1;
+    }
+}
+
+#endif // defined(WIN32)
diff --git a/tools/ioemu/iodev/soundwin.h b/tools/ioemu/iodev/soundwin.h
new file mode 100644 (file)
index 0000000..122fa55
--- /dev/null
@@ -0,0 +1,229 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: soundwin.h,v 1.3 2001/10/03 13:10:38 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+// This file (SOUNDWIN.H) written and donated by Josef Drexler
+
+
+#if defined(WIN32)
+
+#include "bochs.h"
+#include <windows.h>
+
+// uncomment one of the following two #defines
+//#define usesndPlaySnd
+#define usewaveOut
+
+#define BX_SOUND_WINDOWS_MAXSYSEXLEN  256    // maximum supported length of a sysex message
+
+#define BX_SOUND_WINDOWS_NBUF  4   // number of buffers for the output, must be power of 2 and >= 4
+#define BX_SOUND_WINDOWS_NMASK (BX_SOUND_WINDOWS_NBUF - 1)
+
+#ifndef WAVEMAPPER
+#define WAVEMAPPER             -1
+#endif
+
+// Definitions for WINMM.DLL, if not defined already
+#ifndef MMSYSERR_NOERROR
+
+#pragma pack(1)
+
+typedef UINT HMIDIOUT;
+typedef        HMIDIOUT *LPHMIDIOUT;
+typedef struct midihdr_tag {
+    LPSTR lpData;
+    DWORD dwBufferLength;
+    DWORD dwBytesRecorded;
+    DWORD dwUser;
+    DWORD dwFlags;
+    struct midihdr_tag *lpNext;
+    DWORD reserved;
+} MIDIHDR, *LPMIDIHDR;
+
+typedef UINT HWAVEOUT;
+typedef HWAVEOUT *LPHWAVEOUT;
+
+typedef struct wavehdr_tag {
+    LPSTR lpData;
+    DWORD dwBufferLength;
+    DWORD dwBytesRecorded;
+    DWORD dwUser;
+    DWORD dwFlags;
+    DWORD dwLoops;
+    struct wavehdr_tag *lpNext;
+    DWORD reserved;
+} WAVEHDR, *LPWAVEHDR;
+
+#define WHDR_DONE         0x00000001
+#define WHDR_PREPARED     0x00000002
+#define WHDR_BEGINLOOP    0x00000004
+#define WHDR_ENDLOOP      0x00000008
+#define WHDR_INQUEUE      0x00000010
+
+
+typedef struct waveformat_tag {
+    WORD wFormatTag;
+    WORD nChannels;
+    DWORD nSamplesPerSec;
+    DWORD nAvgBytesPerSec;
+    WORD nBlockAlign;
+} WAVEFORMAT, *LPWAVEFORMAT;
+
+#define WAVE_FORMAT_PCM        1
+
+typedef struct pcmwaveformat_tag {
+    WAVEFORMAT wf;
+    WORD wBitsPerSample;
+} PCMWAVEFORMAT, *LPPCMWAVEFORMAT;
+
+#define MIDIMAPPER             -1
+
+#define CALLBACK_NULL          0x00000000
+#define CALLBACK_WINDOW                0x00010000
+#define CALLBACK_TASK          0x00020000
+#define CALLBACK_FUNCTION      0x00030000
+
+#define MMSYSERR_NOERROR       0
+#define MMSYSERR_ERROR         1
+#define MMSYSERR_BADDEVICEID   2
+#define MMSYSERR_NOTENABLED    3
+#define MMSYSERR_ALLOCATED      4
+#define MMSYSERR_INVALHANDLE   5
+#define MMSYSERR_NODRIVER      6
+#define MMSYSERR_NOMEM         7
+#define MMSYSERR_NOTSUPPORTED  8
+#define MMSYSERR_NOMAP         7
+
+#define MIDIERR_UNPREPARED      64
+#define MIDIERR_STILLPLAYING    65
+#define MIDIERR_NOTREADY       66
+#define MIDIERR_NODEVICE        67
+
+#define WAVERR_BADFORMAT        32
+#define WAVERR_STILLPLAYING     33
+#define WAVERR_UNPREPARED       34
+#define WAVERR_SYNC             35
+
+#define MAXERRORLENGTH         128
+
+extern "C" {
+UINT STDCALL midiOutOpen(LPHMIDIOUT, UINT, DWORD, DWORD, DWORD);
+UINT STDCALL midiOutShortMsg(HMIDIOUT, DWORD);
+UINT STDCALL midiOutLongMsg(HMIDIOUT, LPMIDIHDR, UINT);
+UINT STDCALL midiOutPrepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
+UINT STDCALL midiOutUnprepareHeader(HMIDIOUT, LPMIDIHDR, UINT);
+UINT STDCALL midiOutReset(HMIDIOUT);
+UINT STDCALL midiOutClose(HMIDIOUT);
+
+UINT STDCALL waveOutOpen(LPHWAVEOUT, UINT, LPWAVEFORMAT, DWORD, DWORD, DWORD);
+UINT STDCALL waveOutWrite(HWAVEOUT, LPWAVEHDR, UINT);
+UINT STDCALL waveOutPrepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
+UINT STDCALL waveOutUnprepareHeader(HWAVEOUT, LPWAVEHDR, UINT);
+UINT STDCALL waveOutReset(HWAVEOUT);
+UINT STDCALL waveOutClose(HWAVEOUT);
+
+UINT STDCALL waveOutGetErrorTextA(UINT, LPSTR, UINT);
+
+BOOL STDCALL sndPlaySoundA(LPCSTR, UINT);
+}
+
+typedef struct {
+  char RIFF[4];
+  Bit32u length;
+  char TYPE[4];
+  char chnk[4];
+  Bit32u chnklen;
+  PCMWAVEFORMAT waveformat;
+  char chnk2[4];
+  Bit32u chnk2len;
+  char data[1];
+} WAVEFILEHEADER, *LPWAVEFILEHEADER;
+#pragma pack(0)
+
+#endif  // MMSYSERR_NOERROR defined
+
+class bx_sound_windows_c : public bx_sound_output_c {
+public:
+  bx_sound_windows_c(bx_sb16_c *sb16);
+  BX_SOUND_VIRTUAL ~bx_sound_windows_c();
+
+  // if virtual functions are used, we have to override them
+  // and define our own. Otherwise this file will just implement
+  // the original functions
+#ifdef BX_USE_SOUND_VIRTUAL
+  BX_SOUND_VIRTUAL int    waveready();
+  BX_SOUND_VIRTUAL int    midiready();
+
+  BX_SOUND_VIRTUAL int    openmidioutput(char *device);
+  BX_SOUND_VIRTUAL int    sendmidicommand(int delta, int command, int length, Bit8u data[]);
+  BX_SOUND_VIRTUAL int    closemidioutput();
+
+  BX_SOUND_VIRTUAL int    openwaveoutput(char *device);
+  BX_SOUND_VIRTUAL int    startwaveplayback(int frequency, int bits, int stereo, int format);
+  BX_SOUND_VIRTUAL int    sendwavepacket(int length, Bit8u data[]);
+  BX_SOUND_VIRTUAL int    stopwaveplayback();
+  BX_SOUND_VIRTUAL int    closewaveoutput();
+#endif
+
+private:
+  bx_sb16_c *sb16;
+
+  struct bx_sb16_waveinfo_struct {
+    int frequency;
+    int bits;
+    int stereo;
+    int format;
+  };
+
+  HMIDIOUT MidiOut;       // Midi output device
+  int MidiOpen;           // is it open?
+  HWAVEOUT WaveOut;       // Wave output device
+  int WaveOpen;           // is it open?
+
+  UINT WaveDevice;        // Wave device ID, for waveOutOpen
+
+       // some data for the wave buffers
+  HANDLE DataHandle;          // returned by GlobalAlloc()
+  Bit8u *DataPointer;         // returned by GlobalLock()
+
+  LPWAVEHDR WaveHeader[BX_SOUND_WINDOWS_NBUF];
+  LPSTR WaveData[BX_SOUND_WINDOWS_NBUF];
+  int length[BX_SOUND_WINDOWS_NBUF];                // length of the data in the buffer
+  int needreopen;                                   // if the format has changed
+  int head,tailfull,tailplay;       // These are for three states of the buffers: empty, full, played
+  bx_sb16_waveinfo_struct WaveInfo;                 // format for the next buffer to be played
+  int iswaveready;
+
+       // and the midi buffer for the SYSEX messages
+  LPMIDIHDR MidiHeader;
+  LPSTR MidiData;
+  int ismidiready;
+
+  int playnextbuffer();
+  void checkmidiready();
+  void checkwaveready();
+};
+
+#endif  // defined(WIN32)
diff --git a/tools/ioemu/iodev/state_file.cc b/tools/ioemu/iodev/state_file.cc
new file mode 100644 (file)
index 0000000..f7d0d0f
--- /dev/null
@@ -0,0 +1,136 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: state_file.cc,v 1.9 2001/12/21 19:33:18 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Classes for helping to make checkpoints of the emulator state.
+
+
+
+#include "bochs.h"
+#define LOG_THIS log->
+
+
+
+FILE *state_file::get_handle()
+{
+  BX_INFO(("state_file::get_handle()"));
+  return NULL;
+}
+       
+void state_file::write(Bit8u)
+{
+  BX_PANIC(("state_file::write(Bit8u)"));
+}
+
+void state_file::write(Bit16u)
+{
+  BX_PANIC(("state_file::write(Bit16u)"));
+}
+
+void state_file::write(Bit32u)
+{
+  BX_PANIC(("state_file::write(Bit32u)"));
+}
+
+void state_file::write(Bit64u)
+{
+  BX_PANIC(("state_file::write(Bit64u)"));
+}
+
+void state_file::write(const void *, size_t)
+{
+  BX_PANIC(("state_file::write(const void *, size_t)"));
+}
+
+void state_file::read(Bit8u &)
+{
+  BX_PANIC(("state_file::read(uint8 &)"));
+}
+
+void state_file::read(Bit16u &)
+{
+  BX_PANIC(("state_file::read(uint16 &)"));
+}
+
+void state_file::read(Bit32u &)
+{
+  BX_PANIC(("state_file::read(uint32 &)"));
+}
+
+void state_file::read(Bit64u &)
+{
+  BX_PANIC(("state_file::read(uint64 &)"));
+}
+
+void state_file::read(void *, size_t)
+{
+  BX_PANIC(("state_file::read(void *, size_t)"));
+}
+
+void state_file::write_check(const char *)
+{
+  BX_PANIC(("state_file::write_check()"));
+}
+
+void state_file::read_check (const char *)
+{
+  BX_PANIC(("state_file::read_check()"));
+}
+
+void
+state_file::init(void)
+{
+       log = new class logfunctions();
+       log->put("STAT");
+       log->settype(GENLOG);
+}
+
+
+state_file::state_file (const char *name, const char *options)
+{
+  UNUSED(name);
+  UNUSED(options);
+  init();
+  BX_DEBUG(( "Init(const char *, const char *)." ));
+}
+
+state_file::state_file (FILE *f)
+{
+  UNUSED(f);
+  init();
+  BX_INFO(("Init(FILE *)."));
+}
+
+state_file::~state_file()
+{
+  BX_DEBUG(("Exit."));
+  if ( log != NULL )
+  {
+        delete log;
+        log = NULL;
+  }
+}
diff --git a/tools/ioemu/iodev/unmapped.cc b/tools/ioemu/iodev/unmapped.cc
new file mode 100644 (file)
index 0000000..5c7aafe
--- /dev/null
@@ -0,0 +1,305 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: unmapped.cc,v 1.22 2003/08/10 17:19:49 akrisak Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theUnmappedDevice->
+
+
+bx_unmapped_c *theUnmappedDevice = NULL;
+
+  int
+libunmapped_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theUnmappedDevice = new bx_unmapped_c ();
+  bx_devices.pluginUnmapped = theUnmappedDevice;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theUnmappedDevice, BX_PLUGIN_UNMAPPED);
+  return(0); // Success
+}
+
+  void
+libunmapped_LTX_plugin_fini(void)
+{
+}
+
+bx_unmapped_c::bx_unmapped_c(void)
+{
+  put("UNMP");
+  settype(UNMAPLOG);
+  s.port80 = 0x00;
+  s.port8e = 0x00;
+  s.shutdown = 0;
+}
+
+bx_unmapped_c::~bx_unmapped_c(void)
+{
+  // Nothing yet
+}
+
+  void
+bx_unmapped_c::init(void)
+{
+  DEV_register_default_ioread_handler(this, read_handler, "Unmapped", 7);
+  DEV_register_default_iowrite_handler(this, write_handler, "Unmapped", 7);
+}
+
+  void
+bx_unmapped_c::reset(unsigned type)
+{
+}
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_unmapped_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+  bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+  Bit32u
+bx_unmapped_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_UM_SMF
+  UNUSED(io_len);
+
+  Bit32u retval;
+
+  // This function gets called for access to any IO ports which
+  // are not mapped to any device handler.  Reads return 0
+
+  if (address >= 0x02e0 && address <= 0x02ef) {
+       retval = 0;
+       goto return_from_read;
+  }
+
+  switch (address) {
+    case 0x80:
+         retval = BX_UM_THIS s.port80;
+         break;
+    case 0x8e:
+         retval = BX_UM_THIS s.port8e;
+         break;
+#if BX_PORT_E9_HACK
+    // Unused port on ISA - this can be used by the emulated code
+    // to detect it is running inside Bochs and that the debugging
+    // features are available (write 0xFF or something on unused
+    // port 0x80, then read from 0xe9, if value is 0xe9, debug
+    // output is available) (see write() for that) -- Andreas and Emmanuel
+    case 0xe9:
+         retval = 0xe9;
+         break;
+#endif
+    case 0x03df:
+         retval = 0xffffffff;
+      BX_DEBUG(("unsupported IO read from port %04x (CGA)", address));
+      break;
+    case 0x023a:
+    case 0x02f8: /* UART */
+    case 0x02f9: /* UART */
+    case 0x02fb: /* UART */
+    case 0x02fc: /* UART */
+    case 0x02fd: /* UART */
+    case 0x02ea:
+    case 0x02eb:
+    case 0x03e8:
+    case 0x03e9:
+    case 0x03ea:
+    case 0x03eb:
+    case 0x03ec:
+    case 0x03ed:
+    case 0x03f8: /* UART */
+    case 0x03f9: /* UART */
+    case 0x03fb: /* UART */
+    case 0x03fc: /* UART */
+    case 0x03fd: /* UART */
+    case 0x17c6:
+         retval = 0xffffffff;
+      BX_DEBUG(("unsupported IO read from port %04x", address));
+      break;
+    default:
+         retval = 0xffffffff;
+    }
+
+  return_from_read:
+  if (bx_dbg.unsupported_io)
+         switch (io_len) {
+         case 1:
+                 retval = (Bit8u)retval;
+                 BX_DEBUG(("unmapped: 8-bit read from %04x = %02x", address, retval));
+                 break;
+         case 2:
+                 retval = (Bit16u)retval;
+                 BX_DEBUG(("unmapped: 16-bit read from %04x = %04x", address, retval));
+                 break;
+         case 4:
+                 BX_DEBUG(("unmapped: 32-bit read from %04x = %08x", address, retval));
+                 break;
+         default:
+                 BX_DEBUG(("unmapped: %d-bit read from %04x = %x", io_len * 8, address, retval));
+         }
+  return retval;
+}
+
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_unmapped_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_UM_SMF
+  bx_unmapped_c *class_ptr = (bx_unmapped_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len);
+}
+
+  void
+bx_unmapped_c::write(Bit32u address, Bit32u value, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_UM_SMF
+  UNUSED(io_len);
+
+
+  // This function gets called for access to any IO ports which
+  // are not mapped to any device handler.  Writes to an unmapped
+  // IO port are ignored.
+
+// ???
+
+  if (address >= 0x02e0 && address <= 0x02ef)
+       goto return_from_write;
+
+  switch (address) {
+    case 0x80: // diagnostic test port to display progress of POST
+      //BX_DEBUG(("Diagnostic port 80h: write = %02xh", (unsigned) value));
+      BX_UM_THIS s.port80 = value;
+      break;
+
+    case 0x8e: // ???
+      BX_UM_THIS s.port8e = value;
+      break;
+
+#if BX_PORT_E9_HACK
+    // This port doesn't exist on normal ISA architecture. However,
+    // we define a convention here, to display on the console of the
+    // system running Bochs, anything that is written to it. The
+    // idea is to provide debug output very early when writing
+    // BIOS or OS code for example, without having to bother with
+    // properly setting up a serial port or anything.
+    //
+    // Idea by Andreas Beck (andreas.beck@ggi-project.org)
+
+    case 0xe9:
+      putchar(value);
+      fflush(stdout);
+      break;
+#endif
+
+    case 0xed: // Dummy port used as I/O delay
+         break;
+    case 0xee: // ???
+         break;
+
+    case 0x2f2:
+    case 0x2f3:
+    case 0x2f4:
+    case 0x2f5:
+    case 0x2f6:
+    case 0x2f7:
+    case 0x3e8:
+    case 0x3e9:
+    case 0x3eb:
+    case 0x3ec:
+    case 0x3ed:
+           // BX_DEBUG(("unsupported IO write to port %04x of %02x",
+           // address, value));
+      break;
+    
+    case 0x8900: // Shutdown port, could be moved in a PM device
+                 // or a host <-> guest communication device 
+      switch (value) {
+        case 'S': if (BX_UM_THIS s.shutdown == 0) BX_UM_THIS s.shutdown = 1; break;
+        case 'h': if (BX_UM_THIS s.shutdown == 1) BX_UM_THIS s.shutdown = 2; break;
+        case 'u': if (BX_UM_THIS s.shutdown == 2) BX_UM_THIS s.shutdown = 3; break;
+        case 't': if (BX_UM_THIS s.shutdown == 3) BX_UM_THIS s.shutdown = 4; break;
+        case 'd': if (BX_UM_THIS s.shutdown == 4) BX_UM_THIS s.shutdown = 5; break;
+        case 'o': if (BX_UM_THIS s.shutdown == 5) BX_UM_THIS s.shutdown = 6; break;
+        case 'w': if (BX_UM_THIS s.shutdown == 6) BX_UM_THIS s.shutdown = 7; break;
+        case 'n': if (BX_UM_THIS s.shutdown == 7) BX_UM_THIS s.shutdown = 8; break;
+#if BX_DEBUGGER 
+        // Very handy for debugging:
+       // output 'D' to port 8900, and bochs quits to debugger
+        case 'D': bx_debug_break (); break;
+#endif
+       default :  BX_UM_THIS s.shutdown = 0; break;
+        }
+      if (BX_UM_THIS s.shutdown == 8) {
+        bx_user_quit = 1;
+        LOG_THIS setonoff(LOGLEV_PANIC, ACT_FATAL);
+        BX_PANIC(("Shutdown port: shutdown requested"));
+        }
+      break;
+
+    case 0xfedc:
+      bx_dbg.debugger = (value > 0);
+               BX_DEBUG(( "DEBUGGER = %u", (unsigned) bx_dbg.debugger));
+      break;
+
+    default:
+           break;
+    }
+  return_from_write:
+  if (bx_dbg.unsupported_io)
+         switch (io_len) {
+         case 1:
+                 BX_INFO(("unmapped: 8-bit write to %04x = %02x", address, value));
+                 break;
+         case 2:
+                 BX_INFO(("unmapped: 16-bit write to %04x = %04x", address, value));
+                 break;
+         case 4:
+                 BX_INFO(("unmapped: 32-bit write to %04x = %08x", address, value));
+                 break;
+         default:
+                 BX_INFO(("unmapped: %d-bit write to %04x = %x", io_len * 8, address, value));
+                 break;
+         }
+}
diff --git a/tools/ioemu/iodev/unmapped.h b/tools/ioemu/iodev/unmapped.h
new file mode 100644 (file)
index 0000000..c9ef1dc
--- /dev/null
@@ -0,0 +1,64 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: unmapped.h,v 1.10 2002/10/24 21:07:52 bdenney Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+#if BX_USE_UM_SMF
+#  define BX_UM_SMF  static
+#  define BX_UM_THIS theUnmappedDevice->
+#else
+#  define BX_UM_SMF
+#  define BX_UM_THIS this->
+#endif
+
+
+
+class bx_unmapped_c : public bx_devmodel_c {
+public:
+  bx_unmapped_c(void);
+  ~bx_unmapped_c(void);
+
+  virtual void init(void);
+  virtual void reset (unsigned type);
+
+private:
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#if !BX_USE_UM_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+
+  struct {
+    Bit8u port80;
+    Bit8u port8e;
+    Bit8u shutdown;
+    } s;  // state information
+
+  };
diff --git a/tools/ioemu/iodev/vga.cc b/tools/ioemu/iodev/vga.cc
new file mode 100644 (file)
index 0000000..894f80b
--- /dev/null
@@ -0,0 +1,3116 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.cc,v 1.94.2.1 2004/02/02 22:37:48 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
+// platforms that require a special tag on exported symbols, BX_PLUGGABLE 
+// is used to know when we are exporting symbols and when we are importing.
+#define BX_PLUGGABLE
+
+#include "bochs.h"
+
+#define LOG_THIS theVga->
+
+/* NOTES:
+ * I take it data rotate is a true rotate with carry of bit 0 to bit 7.
+ * support map mask (3c5 reg 02)
+ */
+
+/* Notes from cb
+ *
+ * It seems that the vga card should support multi bytes IO reads and write
+ * From my tests, inw(port) return port+1 * 256 + port, except for port 0x3c9
+ * (PEL data register, data cycling). More reverse engineering is needed.
+ * This would fix the gentoo bug.
+ */
+
+// (mch)
+#define VGA_TRACE_FEATURE
+
+// Only reference the array if the tile numbers are within the bounds
+// of the array.  If out of bounds, do nothing.
+#define SET_TILE_UPDATED(xtile,ytile,value)                              \
+  do {                                                                   \
+    if (((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))        \
+      BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)] = value;          \
+  } while (0)
+
+// Only reference the array if the tile numbers are within the bounds
+// of the array.  If out of bounds, return 0.
+#define GET_TILE_UPDATED(xtile,ytile)                                    \
+  ((((xtile) < BX_NUM_X_TILES) && ((ytile) < BX_NUM_Y_TILES))?           \
+     BX_VGA_THIS s.vga_tile_updated[(xtile)][(ytile)]                    \
+     : 0)
+
+static const Bit8u ccdat[16][4] = {
+  { 0x00, 0x00, 0x00, 0x00 },
+  { 0xff, 0x00, 0x00, 0x00 },
+  { 0x00, 0xff, 0x00, 0x00 },
+  { 0xff, 0xff, 0x00, 0x00 },
+  { 0x00, 0x00, 0xff, 0x00 },
+  { 0xff, 0x00, 0xff, 0x00 },
+  { 0x00, 0xff, 0xff, 0x00 },
+  { 0xff, 0xff, 0xff, 0x00 },
+  { 0x00, 0x00, 0x00, 0xff },
+  { 0xff, 0x00, 0x00, 0xff },
+  { 0x00, 0xff, 0x00, 0xff },
+  { 0xff, 0xff, 0x00, 0xff },
+  { 0x00, 0x00, 0xff, 0xff },
+  { 0xff, 0x00, 0xff, 0xff },
+  { 0x00, 0xff, 0xff, 0xff },
+  { 0xff, 0xff, 0xff, 0xff },
+};
+
+bx_vga_c *theVga = NULL;
+
+unsigned old_iHeight = 0, old_iWidth = 0, old_MSL = 0, old_BPP = 0;
+
+  int
+libvga_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
+{
+  theVga = new bx_vga_c ();
+  bx_devices.pluginVgaDevice = theVga;
+  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theVga, BX_PLUGIN_VGA);
+  return(0); // Success
+}
+
+  void
+libvga_LTX_plugin_fini(void)
+{
+}
+
+bx_vga_c::bx_vga_c(void)
+{
+  put("VGA");
+  s.vga_mem_updated = 0;
+  s.x_tilesize = X_TILESIZE;
+  s.y_tilesize = Y_TILESIZE;
+  timer_id = BX_NULL_TIMER_HANDLE;
+}
+
+
+bx_vga_c::~bx_vga_c(void)
+{
+  // nothing for now
+}
+
+
+  void
+bx_vga_c::init(void)
+{
+  unsigned i;
+  unsigned x,y;
+
+  unsigned addr;
+  for (addr=0x03B4; addr<=0x03B5; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+    }
+
+  for (addr=0x03BA; addr<=0x03BA; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+    }
+
+  for (addr=0x03C0; addr<=0x03CF; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+    }
+
+  for (addr=0x03D4; addr<=0x03D5; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+    }
+
+  for (addr=0x03DA; addr<=0x03DA; addr++) {
+    DEV_register_ioread_handler(this, read_handler, addr, "vga video", 1);
+    DEV_register_iowrite_handler(this, write_handler, addr, "vga video", 3);
+    }
+
+
+  BX_VGA_THIS s.misc_output.color_emulation  = 1;
+  BX_VGA_THIS s.misc_output.enable_ram  = 1;
+  BX_VGA_THIS s.misc_output.clock_select     = 0;
+  BX_VGA_THIS s.misc_output.select_high_bank = 0;
+  BX_VGA_THIS s.misc_output.horiz_sync_pol   = 1;
+  BX_VGA_THIS s.misc_output.vert_sync_pol    = 1;
+
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
+
+  BX_VGA_THIS s.line_offset=80;
+  BX_VGA_THIS s.line_compare=1023;
+  BX_VGA_THIS s.vertical_display_end=399;
+
+  for (i=0; i<=0x18; i++)
+    BX_VGA_THIS s.CRTC.reg[i] = 0;
+  BX_VGA_THIS s.CRTC.address = 0;
+
+  BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
+  BX_VGA_THIS s.attribute_ctrl.address = 0;
+  BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
+  for (i=0; i<16; i++)
+    BX_VGA_THIS s.attribute_ctrl.palette_reg[i] = 0;
+  BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
+  BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 0x0f;
+  BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 0;
+  BX_VGA_THIS s.attribute_ctrl.color_select = 0;
+
+  for (i=0; i<256; i++) {
+    BX_VGA_THIS s.pel.data[i].red = 0;
+    BX_VGA_THIS s.pel.data[i].green = 0;
+    BX_VGA_THIS s.pel.data[i].blue = 0;
+    }
+  BX_VGA_THIS s.pel.write_data_register = 0;
+  BX_VGA_THIS s.pel.write_data_cycle = 0;
+  BX_VGA_THIS s.pel.read_data_register = 0;
+  BX_VGA_THIS s.pel.read_data_cycle = 0;
+  BX_VGA_THIS s.pel.dac_state = 0x01;
+  BX_VGA_THIS s.pel.mask = 0xff;
+
+  BX_VGA_THIS s.graphics_ctrl.index = 0;
+  BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
+  BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
+  BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
+  BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
+  BX_VGA_THIS s.graphics_ctrl.raster_op    = 0;
+  BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
+  BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
+  BX_VGA_THIS s.graphics_ctrl.read_mode  = 0;
+  BX_VGA_THIS s.graphics_ctrl.odd_even = 0;
+  BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 0;
+  BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
+  BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
+  BX_VGA_THIS s.graphics_ctrl.memory_mapping = 2; // monochrome text mode
+  BX_VGA_THIS s.graphics_ctrl.color_dont_care = 0;
+  BX_VGA_THIS s.graphics_ctrl.bitmask = 0;
+  for (i=0; i<4; i++) {
+    BX_VGA_THIS s.graphics_ctrl.latch[i] = 0;
+    }
+
+  BX_VGA_THIS s.sequencer.index = 0;
+  BX_VGA_THIS s.sequencer.map_mask = 0;
+  for (i=0; i<4; i++) {
+    BX_VGA_THIS s.sequencer.map_mask_bit[i] = 0;
+    }
+  BX_VGA_THIS s.sequencer.reset1 = 1;
+  BX_VGA_THIS s.sequencer.reset2 = 1;
+  BX_VGA_THIS s.sequencer.reg1 = 0;
+  BX_VGA_THIS s.sequencer.char_map_select = 0;
+  BX_VGA_THIS s.sequencer.extended_mem = 1; // display mem greater than 64K
+  BX_VGA_THIS s.sequencer.odd_even = 1; // use sequential addressing mode
+  BX_VGA_THIS s.sequencer.chain_four = 0; // use map mask & read map select
+
+  memset(BX_VGA_THIS s.vga_memory, 0, sizeof(BX_VGA_THIS s.vga_memory));
+
+  BX_VGA_THIS s.vga_mem_updated = 0;
+  for (y=0; y<480/Y_TILESIZE; y++)
+    for (x=0; x<640/X_TILESIZE; x++)
+      SET_TILE_UPDATED (x, y, 0);
+
+  {
+  /* ??? should redo this to pass X args */
+  char *argv[1] = { "bochs" };
+  bx_gui->init(1, &argv[0], BX_VGA_THIS s.x_tilesize, BX_VGA_THIS s.y_tilesize);
+  }
+
+  BX_INFO(("interval=%u", bx_options.Ovga_update_interval->get ()));
+  if (BX_VGA_THIS timer_id == BX_NULL_TIMER_HANDLE) {
+    BX_VGA_THIS timer_id = bx_pc_system.register_timer(this, timer_handler,
+       bx_options.Ovga_update_interval->get (), 1, 1, "vga");
+  }
+
+  /* video card with BIOS ROM */
+  DEV_cmos_set_reg(0x14, (DEV_cmos_get_reg(0x14) & 0xcf) | 0x00); 
+
+  BX_VGA_THIS s.charmap_address = 0;
+  BX_VGA_THIS s.x_dotclockdiv2 = 0;
+  BX_VGA_THIS s.y_doublescan = 0;
+
+#if BX_SUPPORT_VBE  
+  // The following is for the vbe display extension
+  
+  for (addr=VBE_DISPI_IOPORT_INDEX; addr<=VBE_DISPI_IOPORT_DATA; addr++) {
+    DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
+    DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
+  }    
+#if !BX_PCI_USB_SUPPORT
+  for (addr=VBE_DISPI_IOPORT_INDEX_OLD; addr<=VBE_DISPI_IOPORT_DATA_OLD; addr++) {
+    DEV_register_ioread_handler(this, vbe_read_handler, addr, "vga video", 7);
+    DEV_register_iowrite_handler(this, vbe_write_handler, addr, "vga video", 7);
+  }    
+#endif
+  BX_VGA_THIS s.vbe_cur_dispi=VBE_DISPI_ID0;
+  BX_VGA_THIS s.vbe_xres=640;
+  BX_VGA_THIS s.vbe_yres=480;
+  BX_VGA_THIS s.vbe_bpp=8;
+  BX_VGA_THIS s.vbe_bank=0;
+  BX_VGA_THIS s.vbe_enabled=0;
+  BX_VGA_THIS s.vbe_curindex=0;
+  BX_VGA_THIS s.vbe_offset_x=0;
+  BX_VGA_THIS s.vbe_offset_y=0;
+  BX_VGA_THIS s.vbe_virtual_xres=640;
+  BX_VGA_THIS s.vbe_virtual_yres=480;
+  BX_VGA_THIS s.vbe_bpp_multiplier=1;
+  BX_VGA_THIS s.vbe_virtual_start=0;
+  BX_VGA_THIS s.vbe_line_byte_width=640;
+  BX_VGA_THIS s.vbe_lfb_enabled=0;
+
+  
+  BX_INFO(("VBE Bochs Display Extension Enabled"));
+#endif  
+  bios_init();
+}
+
+  void
+bx_vga_c::bios_init()
+{
+  int i;
+  
+  BX_VGA_THIS s.misc_output.color_emulation = 1;
+  BX_VGA_THIS s.misc_output.enable_ram = 1;
+  BX_VGA_THIS s.misc_output.clock_select = 1;
+  BX_VGA_THIS s.misc_output.select_high_bank = 1;
+  BX_VGA_THIS s.misc_output.horiz_sync_pol = 1;
+  BX_VGA_THIS s.misc_output.vert_sync_pol = 0;
+  BX_VGA_THIS s.CRTC.address = 15;
+  BX_VGA_THIS s.CRTC.reg[0] = 95;
+  BX_VGA_THIS s.CRTC.reg[1] = 79;
+  BX_VGA_THIS s.CRTC.reg[2] = 80;
+  BX_VGA_THIS s.CRTC.reg[3] = 130;
+  BX_VGA_THIS s.CRTC.reg[4] = 85;
+  BX_VGA_THIS s.CRTC.reg[5] = 129;
+  BX_VGA_THIS s.CRTC.reg[6] = 191;
+  BX_VGA_THIS s.CRTC.reg[7] = 31;
+  BX_VGA_THIS s.CRTC.reg[8] = 0;
+  BX_VGA_THIS s.CRTC.reg[9] = 79;
+  BX_VGA_THIS s.CRTC.reg[10] = 14;
+  BX_VGA_THIS s.CRTC.reg[11] = 15;
+  BX_VGA_THIS s.CRTC.reg[12] = 0;
+  BX_VGA_THIS s.CRTC.reg[13] = 0;
+  BX_VGA_THIS s.CRTC.reg[14] = 5;
+  BX_VGA_THIS s.CRTC.reg[15] = 160;
+  BX_VGA_THIS s.CRTC.reg[16] = 156;
+  BX_VGA_THIS s.CRTC.reg[17] = 142;
+  BX_VGA_THIS s.CRTC.reg[18] = 143;
+  BX_VGA_THIS s.CRTC.reg[19] = 40;
+  BX_VGA_THIS s.CRTC.reg[20] = 31;
+  BX_VGA_THIS s.CRTC.reg[21] = 150;
+  BX_VGA_THIS s.CRTC.reg[22] = 185;
+  BX_VGA_THIS s.CRTC.reg[23] = 163;
+  BX_VGA_THIS s.CRTC.reg[24] = 255;
+  BX_VGA_THIS s.attribute_ctrl.flip_flop = 1;
+  BX_VGA_THIS s.attribute_ctrl.address = 0;
+  BX_VGA_THIS s.attribute_ctrl.video_enabled = 1;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[0] = 0;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[1] = 1;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[2] = 2;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[3] = 3;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[4] = 4;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[5] = 5;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[6] = 6;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[7] = 7;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[8] = 8;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[9] = 9;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[10] = 10;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[11] = 11;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[12] = 12;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[13] = 13;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[14] = 14;
+  BX_VGA_THIS s.attribute_ctrl.palette_reg[15] = 15;
+  BX_VGA_THIS s.attribute_ctrl.overscan_color = 0;
+  BX_VGA_THIS s.attribute_ctrl.color_plane_enable = 15;
+  BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = 8;
+  BX_VGA_THIS s.attribute_ctrl.color_select = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics = 1;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity = 1;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 0;
+  BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size = 0;
+  BX_VGA_THIS s.pel.write_data_register = 16;
+  BX_VGA_THIS s.pel.write_data_cycle = 0;
+  BX_VGA_THIS s.pel.read_data_register = 0;
+  BX_VGA_THIS s.pel.read_data_cycle = 0;
+  BX_VGA_THIS s.pel.dac_state = 0;
+  memset((BX_VGA_THIS s.pel.data), 0, 256);
+  BX_VGA_THIS s.pel.data[0].red = 0;
+  BX_VGA_THIS s.pel.data[0].green = 0;
+  BX_VGA_THIS s.pel.data[0].blue = 0;
+  BX_VGA_THIS s.pel.mask = 255;
+  BX_VGA_THIS s.graphics_ctrl.index = 6;
+  BX_VGA_THIS s.graphics_ctrl.set_reset = 0;
+  BX_VGA_THIS s.graphics_ctrl.enable_set_reset = 0;
+  BX_VGA_THIS s.graphics_ctrl.color_compare = 0;
+  BX_VGA_THIS s.graphics_ctrl.data_rotate = 0;
+  BX_VGA_THIS s.graphics_ctrl.raster_op = 0;
+  BX_VGA_THIS s.graphics_ctrl.read_map_select = 0;
+  BX_VGA_THIS s.graphics_ctrl.write_mode = 0;
+  BX_VGA_THIS s.graphics_ctrl.read_mode = 0;
+  BX_VGA_THIS s.graphics_ctrl.odd_even = 1;
+  BX_VGA_THIS s.graphics_ctrl.chain_odd_even = 1;
+  BX_VGA_THIS s.graphics_ctrl.shift_reg = 0;
+  BX_VGA_THIS s.graphics_ctrl.graphics_alpha = 0;
+  BX_VGA_THIS s.graphics_ctrl.memory_mapping = 3;
+  BX_VGA_THIS s.graphics_ctrl.color_dont_care = 15;
+  BX_VGA_THIS s.graphics_ctrl.bitmask = 255;
+  BX_VGA_THIS s.graphics_ctrl.latch[0] = 0;
+  BX_VGA_THIS s.graphics_ctrl.latch[1] = 0;
+  BX_VGA_THIS s.graphics_ctrl.latch[2] = 0;
+  BX_VGA_THIS s.graphics_ctrl.latch[3] = 0;
+  BX_VGA_THIS s.sequencer.index = 3;
+  BX_VGA_THIS s.sequencer.map_mask = 3;
+  BX_VGA_THIS s.sequencer.map_mask_bit[0] = 1;
+  BX_VGA_THIS s.sequencer.map_mask_bit[1] = 1;
+  BX_VGA_THIS s.sequencer.map_mask_bit[2] = 0;
+  BX_VGA_THIS s.sequencer.map_mask_bit[3] = 0;
+  BX_VGA_THIS s.sequencer.reset1 = 1;
+  BX_VGA_THIS s.sequencer.reset2 = 1;
+  BX_VGA_THIS s.sequencer.reg1 = 0;
+  BX_VGA_THIS s.sequencer.char_map_select = 0;
+  BX_VGA_THIS s.sequencer.extended_mem = 1;
+  BX_VGA_THIS s.sequencer.odd_even = 0;
+  BX_VGA_THIS s.sequencer.chain_four = 0;
+  BX_VGA_THIS s.vga_mem_updated = 1;
+  BX_VGA_THIS s.x_tilesize = 16;
+  BX_VGA_THIS s.y_tilesize = 24;
+  BX_VGA_THIS s.line_offset = 160;
+  BX_VGA_THIS s.line_compare = 1023;
+  BX_VGA_THIS s.vertical_display_end = 399;
+  memset((BX_VGA_THIS s.vga_tile_updated), 0, BX_NUM_X_TILES * BX_NUM_Y_TILES);
+  
+  memset((BX_VGA_THIS s.vga_memory), ' ', 256 * 1024);
+  for(i = 0; i < 256 * 1024;i+=2) {
+       BX_VGA_THIS s.vga_memory[i] = ' ';
+       BX_VGA_THIS s.vga_memory[i+1] = 0x07;
+  
+  }
+  memset((BX_VGA_THIS s.text_snapshot), 0, 32 * 1024);
+  memset((BX_VGA_THIS s.rgb), 0, 3 * 256);
+  memset((BX_VGA_THIS s.tile), 0, X_TILESIZE * Y_TILESIZE * 4);
+  BX_VGA_THIS s.charmap_address = 0;
+  BX_VGA_THIS s.x_dotclockdiv2 = 0;
+  BX_VGA_THIS s.y_doublescan = 1;
+}
+
+  void
+bx_vga_c::reset(unsigned type)
+{
+}
+
+
+  void
+bx_vga_c::determine_screen_dimensions(unsigned *piHeight, unsigned *piWidth)
+{
+  int ai[0x20];
+  int i,h,v;
+  for ( i = 0 ; i < 0x20 ; i++ )
+   ai[i] = BX_VGA_THIS s.CRTC.reg[i];
+
+  h = (ai[1] + 1) * 8;
+  v = (ai[18] | ((ai[7] & 0x02) << 7) | ((ai[7] & 0x40) << 3)) + 1;
+
+  if ( BX_VGA_THIS s.graphics_ctrl.shift_reg == 0 )
+    {
+    *piWidth = 640;
+    *piHeight = 480;
+
+    if ( BX_VGA_THIS s.CRTC.reg[6] == 0xBF )
+      {
+      if (BX_VGA_THIS s.CRTC.reg[23] == 0xA3 &&
+         BX_VGA_THIS s.CRTC.reg[20] == 0x40 &&
+         BX_VGA_THIS s.CRTC.reg[9] == 0x41)
+        {
+        *piWidth = 320;
+        *piHeight = 240;
+        }
+      else {
+        if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
+        *piWidth = h;
+        *piHeight = v;
+        }
+      }
+    else if ((h >= 640) && (v >= 480)) {
+      *piWidth = h;
+      *piHeight = v;
+      }
+    }
+  else if ( BX_VGA_THIS s.graphics_ctrl.shift_reg == 2 )
+    {
+
+    if ( BX_VGA_THIS s.sequencer.chain_four )
+      {
+      *piWidth = h;
+      *piHeight = v;
+      }
+    else
+      {
+      *piWidth = h;
+      *piHeight = v;
+      }
+    }
+  else
+    {
+    if (BX_VGA_THIS s.x_dotclockdiv2) h <<= 1;
+    *piWidth = h;
+    *piHeight = v;
+    }
+}
+
+
+  // static IO port read callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  Bit32u
+bx_vga_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  return( class_ptr->read(address, io_len) );
+}
+
+
+  Bit32u
+bx_vga_c::read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_VGA_SMF
+  bx_bool  horiz_retrace = 0, vert_retrace = 0;
+  Bit64u usec;
+  Bit16u vertres;
+  Bit8u retval;
+
+#if defined(VGA_TRACE_FEATURE)
+  Bit32u ret = 0;
+#define RETURN(x) do { ret = (x); goto read_return; } while (0)
+#else
+#define RETURN return
+#endif
+
+#ifdef __OS2__
+  if ( bx_options.videomode == BX_VIDEO_DIRECT )
+     {
+     return _inp(address);
+     }
+#endif
+
+#if !defined(VGA_TRACE_FEATURE)
+    BX_DEBUG(("io read from 0x%04x", (unsigned) address));
+#endif
+
+  if ( (address >= 0x03b0) && (address <= 0x03bf) &&
+       (BX_VGA_THIS s.misc_output.color_emulation) ) {
+       RETURN(0xff);
+  }
+  if ( (address >= 0x03d0) && (address <= 0x03df) &&
+       (BX_VGA_THIS s.misc_output.color_emulation==0) ) {
+       RETURN(0xff);
+  }
+
+  switch (address) {
+    case 0x03ba: /* Input Status 1 (monochrome emulation modes) */
+    case 0x03ca: /* Feature Control ??? */
+    case 0x03da: /* Input Status 1 (color emulation modes) */
+      // bit3: Vertical Retrace
+      //       0 = display is in the display mode
+      //       1 = display is in the vertical retrace mode
+      // bit0: Display Enable
+      //       0 = display is in the display mode
+      //       1 = display is not in the display mode; either the
+      //           horizontal or vertical retrace period is active
+
+      // using 72 Hz vertical frequency
+      usec = bx_pc_system.time_usec();
+      switch ( ( BX_VGA_THIS s.misc_output.vert_sync_pol << 1) | BX_VGA_THIS s.misc_output.horiz_sync_pol )
+      {
+        case 0: vertres = 200; break;
+        case 1: vertres = 400; break;
+        case 2: vertres = 350; break;
+        default: vertres = 480; break;
+      }
+      if ((usec % 13888) < 70) {
+        vert_retrace = 1;
+      }
+      if ((usec % (13888 / vertres)) == 0) {
+        horiz_retrace = 1;
+      }
+
+      retval = 0;
+      if (horiz_retrace || vert_retrace)
+        retval = 0x01;
+      if (vert_retrace)
+        retval |= 0x08;
+
+      /* reading this port resets the flip-flop to address mode */
+      BX_VGA_THIS s.attribute_ctrl.flip_flop = 0;
+      RETURN(retval);
+      break;
+
+
+    case 0x03c0: /* */
+      if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) {
+        //BX_INFO(("io read: 0x3c0: flip_flop = 0"));
+        retval =
+          (BX_VGA_THIS s.attribute_ctrl.video_enabled << 5) |
+          BX_VGA_THIS s.attribute_ctrl.address;
+        RETURN(retval);
+        }
+      else {
+        BX_ERROR(("io read: 0x3c0: flip_flop != 0"));
+        return(0);
+        }
+      break;
+
+    case 0x03c1: /* */
+      switch (BX_VGA_THIS s.attribute_ctrl.address) {
+        case 0x00: case 0x01: case 0x02: case 0x03:
+        case 0x04: case 0x05: case 0x06: case 0x07:
+        case 0x08: case 0x09: case 0x0a: case 0x0b:
+        case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+          retval = BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address];
+         RETURN(retval);
+          break;
+        case 0x10: /* mode control register */
+          retval =
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha << 0) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type << 1) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics << 2) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity << 3) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat << 5) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select << 6) |
+            (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size << 7);
+         RETURN(retval);
+          break;
+       case 0x11: /* overscan color register */
+         RETURN(BX_VGA_THIS s.attribute_ctrl.overscan_color);
+          break;
+       case 0x12: /* color plane enable */
+         RETURN(BX_VGA_THIS s.attribute_ctrl.color_plane_enable);
+          break;
+        case 0x13: /* horizontal PEL panning register */
+          RETURN(BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning);
+          break;
+        case 0x14: /* color select register */
+          RETURN(BX_VGA_THIS s.attribute_ctrl.color_select);
+          break;
+        default:
+          BX_INFO(("io read: 0x3c1: unknown register 0x%02x",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
+          RETURN(0);
+        }
+      break;
+
+    case 0x03c2: /* Input Status 0 */
+      BX_DEBUG(("io read 0x3c2: input status #0: ignoring"));
+      RETURN(0);
+      break;
+
+    case 0x03c3: /* VGA Enable Register */
+      RETURN(1);
+      break;
+
+    case 0x03c4: /* Sequencer Index Register */
+      RETURN(BX_VGA_THIS s.sequencer.index);
+      break;
+
+    case 0x03c5: /* Sequencer Registers 00..04 */
+      switch (BX_VGA_THIS s.sequencer.index) {
+        case 0: /* sequencer: reset */
+          BX_DEBUG(("io read 0x3c5: sequencer reset"));
+          RETURN(BX_VGA_THIS s.sequencer.reset1 | (BX_VGA_THIS s.sequencer.reset2<<1));
+          break;
+        case 1: /* sequencer: clocking mode */
+          BX_DEBUG(("io read 0x3c5: sequencer clocking mode"));
+          RETURN(BX_VGA_THIS s.sequencer.reg1);
+          break;
+        case 2: /* sequencer: map mask register */
+          RETURN(BX_VGA_THIS s.sequencer.map_mask);
+          break;
+        case 3: /* sequencer: character map select register */
+          RETURN(BX_VGA_THIS s.sequencer.char_map_select);
+          break;
+        case 4: /* sequencer: memory mode register */
+          retval =
+            (BX_VGA_THIS s.sequencer.extended_mem   << 1) |
+            (BX_VGA_THIS s.sequencer.odd_even       << 2) |
+            (BX_VGA_THIS s.sequencer.chain_four     << 3);
+          RETURN(retval);
+          break;
+
+        default:
+          BX_DEBUG(("io read 0x3c5: index %u unhandled",
+            (unsigned) BX_VGA_THIS s.sequencer.index));
+          RETURN(0);
+        }
+      break;
+
+    case 0x03c6: /* PEL mask ??? */
+      RETURN(BX_VGA_THIS s.pel.mask);
+      break;
+
+    case 0x03c7: /* DAC state, read = 11b, write = 00b */
+      RETURN(BX_VGA_THIS s.pel.dac_state);
+      break;
+
+    case 0x03c8: /* PEL address write mode */
+      RETURN(BX_VGA_THIS s.pel.write_data_register);
+      break;
+
+    case 0x03c9: /* PEL Data Register, colors 00..FF */
+      if (BX_VGA_THIS s.pel.dac_state == 0x03) {
+        switch (BX_VGA_THIS s.pel.read_data_cycle) {
+          case 0:
+            retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].red;
+            break;
+          case 1:
+            retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].green;
+            break;
+          case 2:
+            retval = BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.read_data_register].blue;
+            break;
+          default:
+            retval = 0; // keep compiler happy
+          }
+        BX_VGA_THIS s.pel.read_data_cycle++;
+        if (BX_VGA_THIS s.pel.read_data_cycle >= 3) {
+          BX_VGA_THIS s.pel.read_data_cycle = 0;
+          BX_VGA_THIS s.pel.read_data_register++;
+          }
+       }
+      else {
+        retval = 0x3f;
+        }
+      RETURN(retval);
+      break;
+
+    case 0x03cc: /* Miscellaneous Output / Graphics 1 Position ??? */
+      retval =
+        ((BX_VGA_THIS s.misc_output.color_emulation  & 0x01) << 0) |
+        ((BX_VGA_THIS s.misc_output.enable_ram       & 0x01) << 1) |
+        ((BX_VGA_THIS s.misc_output.clock_select     & 0x03) << 2) |
+        ((BX_VGA_THIS s.misc_output.select_high_bank & 0x01) << 5) |
+        ((BX_VGA_THIS s.misc_output.horiz_sync_pol   & 0x01) << 6) |
+        ((BX_VGA_THIS s.misc_output.vert_sync_pol    & 0x01) << 7);
+      RETURN(retval);
+      break;
+
+    case 0x03ce: /* Graphics Controller Index Register */
+      RETURN(BX_VGA_THIS s.graphics_ctrl.index);
+      break;
+
+    case 0x03cd: /* ??? */
+      BX_DEBUG(("io read from 03cd"));
+      RETURN(0x00);
+      break;
+
+    case 0x03cf: /* Graphics Controller Registers 00..08 */
+      switch (BX_VGA_THIS s.graphics_ctrl.index) {
+        case 0: /* Set/Reset */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.set_reset);
+          break;
+        case 1: /* Enable Set/Reset */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.enable_set_reset);
+          break;
+        case 2: /* Color Compare */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.color_compare);
+          break;
+        case 3: /* Data Rotate */
+          retval =
+            ((BX_VGA_THIS s.graphics_ctrl.raster_op & 0x03) << 3) |
+            ((BX_VGA_THIS s.graphics_ctrl.data_rotate & 0x07) << 0);
+          RETURN(retval);
+          break;
+        case 4: /* Read Map Select */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.read_map_select);
+          break;
+        case 5: /* Mode */
+          retval =
+            ((BX_VGA_THIS s.graphics_ctrl.shift_reg & 0x03) << 5) |
+            ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01 ) << 4) |
+            ((BX_VGA_THIS s.graphics_ctrl.read_mode & 0x01) << 3) |
+            ((BX_VGA_THIS s.graphics_ctrl.write_mode & 0x03) << 0);
+
+          if (BX_VGA_THIS s.graphics_ctrl.odd_even ||
+              BX_VGA_THIS s.graphics_ctrl.shift_reg)
+            BX_DEBUG(("io read 0x3cf: reg 05 = 0x%02x", (unsigned) retval));
+          RETURN(retval);
+          break;
+        case 6: /* Miscellaneous */
+          retval =
+            ((BX_VGA_THIS s.graphics_ctrl.memory_mapping & 0x03 ) << 2) |
+            ((BX_VGA_THIS s.graphics_ctrl.odd_even & 0x01) << 1) |
+            ((BX_VGA_THIS s.graphics_ctrl.graphics_alpha & 0x01) << 0);
+          RETURN(retval);
+          break;
+        case 7: /* Color Don't Care */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.color_dont_care);
+          break;
+        case 8: /* Bit Mask */
+          RETURN(BX_VGA_THIS s.graphics_ctrl.bitmask);
+          break;
+        default:
+          /* ??? */
+          BX_DEBUG(("io read: 0x3cf: index %u unhandled",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
+          RETURN(0);
+        }
+      break;
+
+    case 0x03d4: /* CRTC Index Register (color emulation modes) */
+      RETURN(BX_VGA_THIS s.CRTC.address);
+      break;
+
+    case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
+    case 0x03d5: /* CRTC Registers (color emulation modes) */
+      if (BX_VGA_THIS s.CRTC.address > 0x18) {
+        BX_DEBUG(("io read: invalid CRTC register 0x%02x",
+          (unsigned) BX_VGA_THIS s.CRTC.address));
+        RETURN(0);
+      }
+      RETURN(BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]);
+      break;
+
+    case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
+    case 0x03cb: /* not sure but OpenBSD reads it a lot */
+    default:
+      BX_INFO(("io read from vga port 0x%02x", (unsigned) address));
+      RETURN(0); /* keep compiler happy */
+    }
+
+#if defined(VGA_TRACE_FEATURE)
+  read_return:
+       BX_DEBUG(("8-bit read from %04x = %02x", (unsigned) address, ret));
+  return ret;
+#endif
+}
+#if defined(VGA_TRACE_FEATURE)
+#undef RETURN
+#endif
+
+  // static IO port write callback handler
+  // redirects to non-static class handler to avoid virtual functions
+
+  void
+bx_vga_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len, 0);
+#else
+  UNUSED(this_ptr);
+  theVga->write(address, value, io_len, 0);
+#endif
+}
+
+  void
+bx_vga_c::write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  class_ptr->write(address, value, io_len, 1);
+#else
+  UNUSED(this_ptr);
+  theVga->write(address, value, io_len, 1);
+#endif
+}
+
+  void
+bx_vga_c::write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log)
+{
+  unsigned i;
+  Bit8u charmap1, charmap2, prev_memory_mapping;
+  bx_bool prev_video_enabled, prev_line_graphics, prev_int_pal_size;
+  bx_bool prev_graphics_alpha, prev_chain_odd_even;
+  bx_bool needs_update = 0;
+
+#if defined(VGA_TRACE_FEATURE)
+  if (!no_log)
+       switch (io_len) {
+             case 1:
+                   BX_DEBUG(("8-bit write to %04x = %02x", (unsigned)address, (unsigned)value));
+                   break;
+             case 2:
+                   BX_DEBUG(("16-bit write to %04x = %04x", (unsigned)address, (unsigned)value));
+                   break;
+             default:
+                   BX_PANIC(("Weird VGA write size"));
+       }
+#else
+  if (io_len == 1) {
+    BX_DEBUG(("io write to 0x%04x = 0x%02x", (unsigned) address,
+      (unsigned) value));
+  }
+#endif
+
+  if (io_len == 2) {
+#if BX_USE_VGA_SMF
+    bx_vga_c::write_handler_no_log(0, address, value & 0xff, 1);
+    bx_vga_c::write_handler_no_log(0, address+1, (value >> 8) & 0xff, 1);
+#else
+    bx_vga_c::write(address, value & 0xff, 1, 1);
+    bx_vga_c::write(address+1, (value >> 8) & 0xff, 1, 1);
+#endif
+    return;
+    }
+
+#ifdef __OS2__
+  if ( bx_options.videomode == BX_VIDEO_DIRECT )
+     {
+     _outp(address,value);
+     return;
+     }
+#endif
+
+  if ( (address >= 0x03b0) && (address <= 0x03bf) &&
+       (BX_VGA_THIS s.misc_output.color_emulation) )
+    return;
+  if ( (address >= 0x03d0) && (address <= 0x03df) &&
+       (BX_VGA_THIS s.misc_output.color_emulation==0) )
+    return;
+
+  switch (address) {
+    case 0x03ba: /* Feature Control (monochrome emulation modes) */
+#if !defined(VGA_TRACE_FEATURE)
+      BX_DEBUG(("io write 3ba: feature control: ignoring"));
+#endif
+      break;
+
+    case 0x03c0: /* Attribute Controller */
+      if (BX_VGA_THIS s.attribute_ctrl.flip_flop == 0) { /* address mode */
+        prev_video_enabled = BX_VGA_THIS s.attribute_ctrl.video_enabled;
+        BX_VGA_THIS s.attribute_ctrl.video_enabled = (value >> 5) & 0x01;
+#if !defined(VGA_TRACE_FEATURE)
+        BX_DEBUG(("io write 3c0: video_enabled = %u",
+                  (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
+#endif
+        if (BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
+          bx_gui->clear_screen();
+        else if (!prev_video_enabled) {
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("found enable transition"));
+#endif
+          needs_update = 1;
+        }
+        value &= 0x1f; /* address = bits 0..4 */
+        BX_VGA_THIS s.attribute_ctrl.address = value;
+        switch (value) {
+          case 0x00: case 0x01: case 0x02: case 0x03:
+          case 0x04: case 0x05: case 0x06: case 0x07:
+          case 0x08: case 0x09: case 0x0a: case 0x0b:
+          case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+            break;
+
+          default:
+            BX_DEBUG(("io write 3c0: address mode reg=%u",
+              (unsigned) value));
+          }
+        }
+      else { /* data-write mode */
+        switch (BX_VGA_THIS s.attribute_ctrl.address) {
+          case 0x00: case 0x01: case 0x02: case 0x03:
+          case 0x04: case 0x05: case 0x06: case 0x07:
+          case 0x08: case 0x09: case 0x0a: case 0x0b:
+          case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+            if (value != BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address]) {
+              BX_VGA_THIS s.attribute_ctrl.palette_reg[BX_VGA_THIS s.attribute_ctrl.address] =
+                value;
+              needs_update = 1;
+            }
+            break;
+          case 0x10: // mode control register
+            prev_line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
+            prev_int_pal_size = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha =
+              (value >> 0) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type =
+              (value >> 1) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics =
+              (value >> 2) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity =
+              (value >> 3) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_panning_compat =
+              (value >> 5) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select =
+              (value >> 6) & 0x01;
+            BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size =
+              (value >> 7) & 0x01;
+            if (((value >> 2) & 0x01) != prev_line_graphics) {
+              bx_gui->set_text_charmap(
+                & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+              BX_VGA_THIS s.vga_mem_updated = 1;
+            }
+            if (((value >> 7) & 0x01) != prev_int_pal_size) {
+              needs_update = 1;
+            }
+#if !defined(VGA_TRACE_FEATURE)
+            BX_DEBUG(("io write 3c0: mode control: %02x h",
+                (unsigned) value));
+#endif
+            break;
+          case 0x11: // Overscan Color Register
+            BX_VGA_THIS s.attribute_ctrl.overscan_color = (value & 0x3f);
+#if !defined(VGA_TRACE_FEATURE)
+            BX_DEBUG(("io write 3c0: overscan color = %02x",
+                        (unsigned) value));
+#endif
+            break;
+          case 0x12: // Color Plane Enable Register
+            BX_VGA_THIS s.attribute_ctrl.color_plane_enable = (value & 0x0f);
+            needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+            BX_DEBUG(("io write 3c0: color plane enable = %02x",
+                        (unsigned) value));
+#endif
+            break;
+          case 0x13: // Horizontal Pixel Panning Register
+            BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning = (value & 0x0f);
+            needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+            BX_DEBUG(("io write 3c0: horiz pel panning = %02x",
+                        (unsigned) value));
+#endif
+            break;
+          case 0x14: // Color Select Register
+            BX_VGA_THIS s.attribute_ctrl.color_select = (value & 0x0f);
+            needs_update = 1;
+#if !defined(VGA_TRACE_FEATURE)
+            BX_DEBUG(("io write 3c0: color select = %02x",
+                        (unsigned) BX_VGA_THIS s.attribute_ctrl.color_select));
+#endif
+            break;
+          default:
+            BX_DEBUG(("io write 3c0: data-write mode %02x h",
+              (unsigned) BX_VGA_THIS s.attribute_ctrl.address));
+          }
+        }
+      BX_VGA_THIS s.attribute_ctrl.flip_flop = !BX_VGA_THIS s.attribute_ctrl.flip_flop;
+      break;
+
+    case 0x03c2: // Miscellaneous Output Register
+      BX_VGA_THIS s.misc_output.color_emulation  = (value >> 0) & 0x01;
+      BX_VGA_THIS s.misc_output.enable_ram       = (value >> 1) & 0x01;
+      BX_VGA_THIS s.misc_output.clock_select     = (value >> 2) & 0x03;
+      BX_VGA_THIS s.misc_output.select_high_bank = (value >> 5) & 0x01;
+      BX_VGA_THIS s.misc_output.horiz_sync_pol   = (value >> 6) & 0x01;
+      BX_VGA_THIS s.misc_output.vert_sync_pol    = (value >> 7) & 0x01;
+#if !defined(VGA_TRACE_FEATURE)
+        BX_DEBUG(("io write 3c2:"));
+        BX_DEBUG(("  color_emulation (attempted) = %u",
+                  (value >> 0) & 0x01));
+        BX_DEBUG(("  enable_ram = %u",
+                  (unsigned) BX_VGA_THIS s.misc_output.enable_ram));
+        BX_DEBUG(("  clock_select = %u",
+                  (unsigned) BX_VGA_THIS s.misc_output.clock_select));
+        BX_DEBUG(("  select_high_bank = %u",
+                  (unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
+        BX_DEBUG(("  horiz_sync_pol = %u",
+                  (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
+        BX_DEBUG(("  vert_sync_pol = %u",
+                  (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
+#endif
+      break;
+
+    case 0x03c3: // VGA enable
+      // bit0: enables VGA display if set
+#if !defined(VGA_TRACE_FEATURE)
+      BX_DEBUG(("io write 3c3: (ignoring) VGA enable = %u",
+                  (unsigned) (value & 0x01) ));
+#endif
+      break;
+
+    case 0x03c4: /* Sequencer Index Register */
+      if (value > 4) {
+        BX_DEBUG(("io write 3c4: value > 4"));
+        }
+      BX_VGA_THIS s.sequencer.index = value;
+      break;
+
+    case 0x03c5: /* Sequencer Registers 00..04 */
+      switch (BX_VGA_THIS s.sequencer.index) {
+        case 0: /* sequencer: reset */
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("write 0x3c5: sequencer reset: value=0x%02x",
+                      (unsigned) value));
+#endif
+          if (BX_VGA_THIS s.sequencer.reset1 && ((value & 0x01) == 0)) {
+            BX_VGA_THIS s.sequencer.char_map_select = 0;
+            BX_VGA_THIS s.charmap_address = 0;
+            bx_gui->set_text_charmap(
+              & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+            BX_VGA_THIS s.vga_mem_updated = 1;
+          }
+          BX_VGA_THIS s.sequencer.reset1 = (value >> 0) & 0x01;
+          BX_VGA_THIS s.sequencer.reset2 = (value >> 1) & 0x01;
+          break;
+        case 1: /* sequencer: clocking mode */
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("io write 3c5=%02x: clocking mode reg: ignoring",
+                      (unsigned) value));
+#endif
+          BX_VGA_THIS s.sequencer.reg1 = value & 0x3f;
+          BX_VGA_THIS s.x_dotclockdiv2 = ((value & 0x08) > 0);
+          break;
+        case 2: /* sequencer: map mask register */
+          BX_VGA_THIS s.sequencer.map_mask = (value & 0x0f);
+          for (i=0; i<4; i++)
+            BX_VGA_THIS s.sequencer.map_mask_bit[i] = (value >> i) & 0x01;
+          break;
+        case 3: /* sequencer: character map select register */
+          BX_VGA_THIS s.sequencer.char_map_select = value;
+          charmap1 = value & 0x13;
+          if (charmap1 > 3) charmap1 = (charmap1 & 3) + 4;
+          charmap2 = (value & 0x2C) >> 2;
+          if (charmap2 > 3) charmap2 = (charmap2 & 3) + 4;
+         if (BX_VGA_THIS s.CRTC.reg[0x09] > 0) {
+            BX_VGA_THIS s.charmap_address = (charmap1 << 13);
+            bx_gui->set_text_charmap(
+              & BX_VGA_THIS s.vga_memory[0x20000 + BX_VGA_THIS s.charmap_address]);
+            BX_VGA_THIS s.vga_mem_updated = 1;
+            }
+          if (charmap2 != charmap1)
+            BX_INFO(("char map select: #2=%d (unused)", charmap2));
+          break;
+        case 4: /* sequencer: memory mode register */
+          BX_VGA_THIS s.sequencer.extended_mem   = (value >> 1) & 0x01;
+          BX_VGA_THIS s.sequencer.odd_even       = (value >> 2) & 0x01;
+          BX_VGA_THIS s.sequencer.chain_four     = (value >> 3) & 0x01;
+
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("io write 3c5: index 4:"));
+          BX_DEBUG(("  extended_mem %u",
+              (unsigned) BX_VGA_THIS s.sequencer.extended_mem));
+          BX_DEBUG(("  odd_even %u",
+              (unsigned) BX_VGA_THIS s.sequencer.odd_even));
+          BX_DEBUG(("  chain_four %u",
+              (unsigned) BX_VGA_THIS s.sequencer.chain_four));
+#endif
+          break;
+        default:
+          BX_DEBUG(("io write 3c5: index %u unhandled",
+            (unsigned) BX_VGA_THIS s.sequencer.index));
+        }
+      break;
+
+    case 0x03c6: /* PEL mask */
+      BX_VGA_THIS s.pel.mask = value;
+      if (BX_VGA_THIS s.pel.mask != 0xff)
+        BX_DEBUG(("io write 3c6: PEL mask=0x%02x != 0xFF", value));
+      // BX_VGA_THIS s.pel.mask should be and'd with final value before
+      // indexing into color register BX_VGA_THIS s.pel.data[]
+      break;
+
+    case 0x03c7: // PEL address, read mode
+      BX_VGA_THIS s.pel.read_data_register = value;
+      BX_VGA_THIS s.pel.read_data_cycle    = 0;
+      BX_VGA_THIS s.pel.dac_state = 0x03;
+      break;
+
+    case 0x03c8: /* PEL address write mode */
+      BX_VGA_THIS s.pel.write_data_register = value;
+      BX_VGA_THIS s.pel.write_data_cycle    = 0;
+      BX_VGA_THIS s.pel.dac_state = 0x00;
+      break;
+
+    case 0x03c9: /* PEL Data Register, colors 00..FF */
+      switch (BX_VGA_THIS s.pel.write_data_cycle) {
+        case 0:
+          BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red = value;
+          break;
+        case 1:
+          BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green = value;
+          break;
+        case 2:
+          BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue = value;
+
+          needs_update |= bx_gui->palette_change(BX_VGA_THIS s.pel.write_data_register,
+            BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red<<2,
+            BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green<<2,
+            BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue<<2);
+          break;
+        }
+
+      BX_VGA_THIS s.pel.write_data_cycle++;
+      if (BX_VGA_THIS s.pel.write_data_cycle >= 3) {
+        //BX_INFO(("BX_VGA_THIS s.pel.data[%u] {r=%u, g=%u, b=%u}",
+        //  (unsigned) BX_VGA_THIS s.pel.write_data_register,
+        //  (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].red,
+        //  (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].green,
+        //  (unsigned) BX_VGA_THIS s.pel.data[BX_VGA_THIS s.pel.write_data_register].blue);
+        BX_VGA_THIS s.pel.write_data_cycle = 0;
+        BX_VGA_THIS s.pel.write_data_register++;
+        }
+      break;
+
+    case 0x03ca: /* Graphics 2 Position (EGA) */
+      // ignore, EGA only???
+      break;
+
+    case 0x03cc: /* Graphics 1 Position (EGA) */
+      // ignore, EGA only???
+      break;
+
+    case 0x03ce: /* Graphics Controller Index Register */
+      if (value > 0x08) /* ??? */
+        BX_DEBUG(("io write: 3ce: value > 8"));
+      BX_VGA_THIS s.graphics_ctrl.index = value;
+      break;
+
+    case 0x03cd: /* ??? */
+      BX_DEBUG(("io write to 03cd = %02x", (unsigned) value));
+      break;
+
+    case 0x03cf: /* Graphics Controller Registers 00..08 */
+      switch (BX_VGA_THIS s.graphics_ctrl.index) {
+        case 0: /* Set/Reset */
+          BX_VGA_THIS s.graphics_ctrl.set_reset = value & 0x0f;
+          break;
+        case 1: /* Enable Set/Reset */
+          BX_VGA_THIS s.graphics_ctrl.enable_set_reset = value & 0x0f;
+          break;
+        case 2: /* Color Compare */
+          BX_VGA_THIS s.graphics_ctrl.color_compare = value & 0x0f;
+          break;
+        case 3: /* Data Rotate */
+          BX_VGA_THIS s.graphics_ctrl.data_rotate = value & 0x07;
+          /* ??? is this bits 3..4 or 4..5 */
+          BX_VGA_THIS s.graphics_ctrl.raster_op    = (value >> 3) & 0x03; /* ??? */
+          break;
+        case 4: /* Read Map Select */
+          BX_VGA_THIS s.graphics_ctrl.read_map_select = value & 0x03;
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("io write to 03cf = %02x (RMS)", (unsigned) value));
+#endif
+          break;
+        case 5: /* Mode */
+          BX_VGA_THIS s.graphics_ctrl.write_mode        = value & 0x03;
+          BX_VGA_THIS s.graphics_ctrl.read_mode         = (value >> 3) & 0x01;
+          BX_VGA_THIS s.graphics_ctrl.odd_even   = (value >> 4) & 0x01;
+          BX_VGA_THIS s.graphics_ctrl.shift_reg         = (value >> 5) & 0x03;
+
+          if (BX_VGA_THIS s.graphics_ctrl.odd_even)
+            BX_DEBUG(("io write: 3cf: reg 05: value = %02xh",
+              (unsigned) value));
+          if (BX_VGA_THIS s.graphics_ctrl.shift_reg)
+            BX_DEBUG(("io write: 3cf: reg 05: value = %02xh",
+              (unsigned) value));
+          break;
+        case 6: /* Miscellaneous */
+          prev_graphics_alpha = BX_VGA_THIS s.graphics_ctrl.graphics_alpha;
+          prev_chain_odd_even = BX_VGA_THIS s.graphics_ctrl.chain_odd_even;
+          prev_memory_mapping = BX_VGA_THIS s.graphics_ctrl.memory_mapping;
+
+          BX_VGA_THIS s.graphics_ctrl.graphics_alpha = value & 0x01;
+          BX_VGA_THIS s.graphics_ctrl.chain_odd_even = (value >> 1) & 0x01;
+          BX_VGA_THIS s.graphics_ctrl.memory_mapping = (value >> 2) & 0x03;
+#if !defined(VGA_TRACE_FEATURE)
+          BX_DEBUG(("memory_mapping set to %u",
+              (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+          BX_DEBUG(("graphics mode set to %u",
+              (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
+          BX_DEBUG(("odd_even mode set to %u",
+              (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
+          BX_DEBUG(("io write: 3cf: reg 06: value = %02xh",
+                (unsigned) value));
+#endif
+          if (prev_memory_mapping != BX_VGA_THIS s.graphics_ctrl.memory_mapping)
+            needs_update = 1;
+          if (prev_graphics_alpha != BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+            needs_update = 1;
+            old_iHeight = 0;
+          }
+          break;
+        case 7: /* Color Don't Care */
+          BX_VGA_THIS s.graphics_ctrl.color_dont_care = value & 0x0f;
+          break;
+        case 8: /* Bit Mask */
+          BX_VGA_THIS s.graphics_ctrl.bitmask = value;
+          break;
+        default:
+          /* ??? */
+          BX_DEBUG(("io write: 3cf: index %u unhandled",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.index));
+        }
+      break;
+
+    case 0x03b4: /* CRTC Index Register (monochrome emulation modes) */
+    case 0x03d4: /* CRTC Index Register (color emulation modes) */
+      BX_VGA_THIS s.CRTC.address = value & 0x7f;
+      if (BX_VGA_THIS s.CRTC.address > 0x18)
+        BX_DEBUG(("write: invalid CRTC register 0x%02x selected",
+          (unsigned) BX_VGA_THIS s.CRTC.address));
+      break;
+
+    case 0x03b5: /* CRTC Registers (monochrome emulation modes) */
+    case 0x03d5: /* CRTC Registers (color emulation modes) */
+      if (BX_VGA_THIS s.CRTC.address > 0x18) {
+        BX_DEBUG(("write: invalid CRTC register 0x%02x ignored",
+          (unsigned) BX_VGA_THIS s.CRTC.address));
+        return;
+      }
+      if (value != BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address]) {
+        BX_VGA_THIS s.CRTC.reg[BX_VGA_THIS s.CRTC.address] = value;
+        switch (BX_VGA_THIS s.CRTC.address) {
+          case 0x07:
+            BX_VGA_THIS s.vertical_display_end &= 0xff;
+            if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x02) BX_VGA_THIS s.vertical_display_end |= 0x100;
+            if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x40) BX_VGA_THIS s.vertical_display_end |= 0x200;
+            BX_VGA_THIS s.line_compare &= 0x2ff;
+            if (BX_VGA_THIS s.CRTC.reg[0x07] & 0x10) BX_VGA_THIS s.line_compare |= 0x100;
+            needs_update = 1;
+            break;
+          case 0x08:
+            // Vertical pel panning change
+            needs_update = 1;
+            break;
+          case 0x09:
+            BX_VGA_THIS s.y_doublescan = ((value & 0x9f) > 0);
+            BX_VGA_THIS s.line_compare &= 0x1ff;
+            if (BX_VGA_THIS s.CRTC.reg[0x09] & 0x40) BX_VGA_THIS s.line_compare |= 0x200;
+            needs_update = 1;
+            break;
+          case 0x0A:
+          case 0x0B:
+          case 0x0E:
+          case 0x0F:
+            // Cursor size / location change
+            BX_VGA_THIS s.vga_mem_updated = 1;
+            break;
+          case 0x0C:
+          case 0x0D:
+            // Start address change
+            if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+              needs_update = 1;
+            } else {
+              BX_VGA_THIS s.vga_mem_updated = 1;
+            }
+            break;
+          case 0x12:
+            BX_VGA_THIS s.vertical_display_end &= 0x300;
+            BX_VGA_THIS s.vertical_display_end |= BX_VGA_THIS s.CRTC.reg[0x12];
+            break;
+          case 0x13:
+          case 0x14:
+          case 0x17:
+            // Line offset change
+            BX_VGA_THIS s.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 1;
+            if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) BX_VGA_THIS s.line_offset <<= 2;
+            else if ((BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) == 0) BX_VGA_THIS s.line_offset <<= 1;
+            needs_update = 1;
+            break;
+          case 0x18:
+            BX_VGA_THIS s.line_compare &= 0x300;
+            BX_VGA_THIS s.line_compare |= BX_VGA_THIS s.CRTC.reg[0x18];
+            needs_update = 1;
+            break;
+        }
+
+      }
+      break;
+
+    case 0x03da: /* Feature Control (color emulation modes) */
+      BX_DEBUG(("io write: 3da: ignoring: feature ctrl & vert sync"));
+      break;
+
+    case 0x03c1: /* */
+    default:
+      BX_ERROR(("unsupported io write to port 0x%04x, val=0x%02x",
+        (unsigned) address, (unsigned) value));
+    }
+  if (needs_update) {
+    BX_VGA_THIS s.vga_mem_updated = 1;
+    // Mark all video as updated so the changes will go through
+    if ((BX_VGA_THIS s.graphics_ctrl.graphics_alpha)
+#if BX_SUPPORT_VBE  
+        || (BX_VGA_THIS s.vbe_enabled)
+#endif
+       ) {
+      for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+        for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+          SET_TILE_UPDATED (xti, yti, 1);
+        }
+      }
+    } else {
+      memset(BX_VGA_THIS s.text_snapshot, 0,
+             sizeof(BX_VGA_THIS s.text_snapshot));
+    }
+  }
+}
+
+void 
+bx_vga_c::set_update_interval (unsigned interval)
+{
+  BX_INFO (("Changing timer interval to %d\n", interval));
+  BX_VGA_THIS timer_handler (theVga);
+  bx_pc_system.activate_timer (BX_VGA_THIS timer_id, interval, 1);
+}
+
+  void
+bx_vga_c::trigger_timer(void *this_ptr)
+{
+  timer_handler(this_ptr);
+}
+
+  void
+bx_vga_c::timer_handler(void *this_ptr)
+{
+#if !BX_USE_VGA_SMF
+  
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  class_ptr->timer();
+}
+
+  void
+bx_vga_c::timer(void)
+{
+#else
+  UNUSED(this_ptr);
+#endif
+
+  update();
+  bx_gui->flush();
+
+}
+
+
+  void
+bx_vga_c::update(void)
+{
+  unsigned iHeight, iWidth;
+
+  /* no screen update necessary */
+  if (BX_VGA_THIS s.vga_mem_updated==0)
+    return;
+
+  /* skip screen update when the sequencer is in reset mode or video is disabled */
+  if (!BX_VGA_THIS s.sequencer.reset1 || !BX_VGA_THIS s.sequencer.reset2
+      || !BX_VGA_THIS s.attribute_ctrl.video_enabled)
+    return;
+
+  /* skip screen update if the vertical retrace is in progress
+     (using 72 Hz vertical frequency) */
+  if ((bx_pc_system.time_usec() % 13888) < 70)
+    return;
+
+#if BX_SUPPORT_VBE  
+  if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+  {
+    // specific VBE code display update code
+    // this is partly copied/modified from the 320x200x8 update more below
+    unsigned xc, yc, xti, yti;
+    unsigned r;
+    unsigned long pixely, bmp_ofs_y, tile_ofs_y;
+
+    if (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_32)
+    {
+      Bit32u *vidmem = (Bit32u *)(&BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start]);
+      Bit32u *tile   = (Bit32u *)(BX_VGA_THIS s.tile);
+      Bit16u width  =  BX_VGA_THIS s.vbe_virtual_xres;
+
+      Bit32u *vidptr, *tileptr;
+
+      iWidth=BX_VGA_THIS s.vbe_xres;
+      iHeight=BX_VGA_THIS s.vbe_yres;
+
+      for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+      {
+        for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+        {
+          if (GET_TILE_UPDATED (xti, yti))
+          {
+            for (r=0; r<Y_TILESIZE; r++)
+            {
+              pixely    = yc + r;
+              // calc offsets into video and tile memory
+              bmp_ofs_y = pixely*width;
+              tile_ofs_y = r*X_TILESIZE;
+              // get offsets so that we do less calc in the inner loop
+              vidptr = &vidmem[bmp_ofs_y+xc];
+              tileptr = &tile[tile_ofs_y];
+              memmove(tileptr, vidptr, X_TILESIZE<<2);
+            }
+            SET_TILE_UPDATED (xti, yti, 0);
+            bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+          }
+        }
+      }
+    }
+    else if (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_24)
+    {
+      Bit8u *vidmem = &BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start];
+      Bit8u *tile   =  BX_VGA_THIS s.tile;
+      Bit16u width  =  BX_VGA_THIS s.vbe_virtual_xres*3;
+
+      Bit8u *vidptr, *tileptr;
+
+      iWidth=BX_VGA_THIS s.vbe_xres;
+      iHeight=BX_VGA_THIS s.vbe_yres;
+
+      for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+      {
+        for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+        {
+          if (GET_TILE_UPDATED (xti, yti))
+          {
+            for (r=0; r<Y_TILESIZE; r++)
+            {
+              pixely    = yc + r;
+              // calc offsets into video and tile memory
+              bmp_ofs_y = pixely*width;
+              tile_ofs_y = r*X_TILESIZE*3;
+              // get offsets so that we do less calc in the inner loop
+              vidptr = &vidmem[bmp_ofs_y+xc*3];
+              tileptr = &tile[tile_ofs_y];
+              memmove(tileptr, vidptr, X_TILESIZE*3);
+            }
+            SET_TILE_UPDATED (xti, yti, 0);
+            bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+          }
+        }
+      }
+    }
+    else if ((BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_15) ||
+             (BX_VGA_THIS s.vbe_bpp == VBE_DISPI_BPP_16))
+    {
+      Bit16u *vidmem = (Bit16u *)(&BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start]);
+      Bit16u *tile   = (Bit16u *)(BX_VGA_THIS s.tile);
+      Bit16u width  =  BX_VGA_THIS s.vbe_virtual_xres;
+
+      Bit16u *vidptr, *tileptr;
+
+      iWidth=BX_VGA_THIS s.vbe_xres;
+      iHeight=BX_VGA_THIS s.vbe_yres;
+
+      for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+      {
+        for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+        {
+          if (GET_TILE_UPDATED (xti, yti))
+          {
+            for (r=0; r<Y_TILESIZE; r++)
+            {
+              pixely    = yc + r;
+              // calc offsets into video and tile memory
+              bmp_ofs_y = pixely*width;
+              tile_ofs_y = r*X_TILESIZE;
+              // get offsets so that we do less calc in the inner loop
+              vidptr = &vidmem[bmp_ofs_y+xc];
+              tileptr = &tile[tile_ofs_y];
+              memmove(tileptr, vidptr, X_TILESIZE<<1);
+            }
+            SET_TILE_UPDATED (xti, yti, 0);
+            bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+          }
+        }
+      }
+    }
+    else /* Update 8bpp mode */
+    {
+      Bit8u *vidmem = &BX_VGA_THIS s.vbe_memory[BX_VGA_THIS s.vbe_virtual_start]; 
+      Bit8u *tile   =  BX_VGA_THIS s.tile;
+      Bit16u width  =  BX_VGA_THIS s.vbe_virtual_xres;
+
+      Bit8u *vidptr, *tileptr;
+
+      iWidth=BX_VGA_THIS s.vbe_xres;
+      iHeight=BX_VGA_THIS s.vbe_yres;
+
+      for (yc=0, yti = 0; yc<iHeight; yc+=Y_TILESIZE, yti++)
+      {
+        for (xc=0, xti = 0; xc<iWidth; xc+=X_TILESIZE, xti++)
+        {
+          // If the tile has not been updated, copy it into the tile buffer for update  
+          if (GET_TILE_UPDATED (xti, yti)) {
+            for (r=0; r<Y_TILESIZE; r++) {
+              // actual video y coord is tile_y + y
+              pixely = yc + r;
+              // calc offsets into video and tile memory
+              bmp_ofs_y = pixely*width;
+              tile_ofs_y = r*X_TILESIZE;
+              // get offsets so that we do less calc in the inner loop
+              vidptr = &vidmem[bmp_ofs_y+xc];
+              tileptr = &tile[tile_ofs_y];
+              memmove(tileptr, vidptr, X_TILESIZE);
+            }
+            SET_TILE_UPDATED (xti, yti, 0);
+            bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+          }
+        }
+      }
+    }
+
+    old_iWidth = iWidth;
+    old_iHeight = iHeight;
+    BX_VGA_THIS s.vga_mem_updated = 0;
+    // after a vbe display update, don't try to do any 'normal vga' updates anymore
+    return;
+  }
+#endif  
+  // fields that effect the way video memory is serialized into screen output:
+  // GRAPHICS CONTROLLER:
+  //   BX_VGA_THIS s.graphics_ctrl.shift_reg:
+  //     0: output data in standard VGA format or CGA-compatible 640x200 2 color
+  //        graphics mode (mode 6)
+  //     1: output data in CGA-compatible 320x200 4 color graphics mode
+  //        (modes 4 & 5)
+  //     2: output data 8 bits at a time from the 4 bit planes
+  //        (mode 13 and variants like modeX)
+
+  // if (BX_VGA_THIS s.vga_mem_updated==0 || BX_VGA_THIS s.attribute_ctrl.video_enabled == 0)
+
+  if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+    Bit8u color;
+    unsigned bit_no, r, c, x, y;
+    unsigned long byte_offset, start_addr;
+    unsigned xc, yc, xti, yti;
+
+    start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
+
+//BX_DEBUG(("update: shiftreg=%u, chain4=%u, mapping=%u",
+//  (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg,
+//  (unsigned) BX_VGA_THIS s.sequencer.chain_four,
+//  (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping);
+
+    determine_screen_dimensions(&iHeight, &iWidth);
+    if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (old_BPP > 8) ) {
+      bx_gui->dimension_update(iWidth, iHeight);
+      old_iWidth = iWidth;
+      old_iHeight = iHeight;
+      old_BPP = 8;
+    }
+
+    switch ( BX_VGA_THIS s.graphics_ctrl.shift_reg ) {
+
+      case 0:
+        Bit8u attribute, palette_reg_val, DAC_regno;
+        unsigned long line_compare;
+
+        if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // CGA 640x200x2
+
+          for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+            for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+              if (GET_TILE_UPDATED (xti, yti)) {
+                for (r=0; r<Y_TILESIZE; r++) {
+                  y = yc + r;
+                  if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+                  for (c=0; c<X_TILESIZE; c++) {
+
+                    x = xc + c;
+                    /* 0 or 0x2000 */
+                    byte_offset = start_addr + ((y & 1) << 13);
+                    /* to the start of the line */
+                    byte_offset += (320 / 4) * (y / 2);
+                    /* to the byte start */
+                    byte_offset += (x / 8);
+
+                    bit_no = 7 - (x % 8);
+                    palette_reg_val = (((BX_VGA_THIS s.vga_memory[byte_offset]) >> bit_no) & 1);
+                    DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
+                    BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+                  }
+                }
+                SET_TILE_UPDATED (xti, yti, 0);
+                bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+              }
+            }
+          }
+        } else { // output data in serial fashion with each display plane
+                 // output on its associated serial output.  Standard EGA/VGA format
+
+          line_compare = BX_VGA_THIS s.line_compare;
+          if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1;
+
+          for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+            for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+              if (GET_TILE_UPDATED (xti, yti)) {
+                for (r=0; r<Y_TILESIZE; r++) {
+                  y = yc + r;
+                  if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+                  for (c=0; c<X_TILESIZE; c++) {
+                    x = xc + c;
+                    if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
+                    bit_no = 7 - (x % 8);
+                    if (y > line_compare) {
+                      byte_offset = x / 8 +
+                        ((y - line_compare - 1) * BX_VGA_THIS s.line_offset);
+                    } else {
+                      byte_offset = start_addr + x / 8 +
+                        (y * BX_VGA_THIS s.line_offset);
+                    }
+                    attribute =
+                      (((BX_VGA_THIS s.vga_memory[0*65536 + byte_offset] >> bit_no) & 0x01) << 0) |
+                      (((BX_VGA_THIS s.vga_memory[1*65536 + byte_offset] >> bit_no) & 0x01) << 1) |
+                      (((BX_VGA_THIS s.vga_memory[2*65536 + byte_offset] >> bit_no) & 0x01) << 2) |
+                      (((BX_VGA_THIS s.vga_memory[3*65536 + byte_offset] >> bit_no) & 0x01) << 3);
+
+                    attribute &= BX_VGA_THIS s.attribute_ctrl.color_plane_enable;
+                    // undocumented feature ???: colors 0..7 high intensity, colors 8..15 blinking
+                    // using low/high intensity. Blinking is not implemented yet.
+                    if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.blink_intensity) attribute ^= 0x08;
+                    palette_reg_val = BX_VGA_THIS s.attribute_ctrl.palette_reg[attribute];
+                    if (BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size) {
+                      // use 4 lower bits from palette register
+                      // use 4 higher bits from color select register
+                      // 16 banks of 16-color registers
+                      DAC_regno = (palette_reg_val & 0x0f) |
+                                  (BX_VGA_THIS s.attribute_ctrl.color_select << 4);
+                      }
+                    else {
+                      // use 6 lower bits from palette register
+                      // use 2 higher bits from color select register
+                      // 4 banks of 64-color registers
+                      DAC_regno = (palette_reg_val & 0x3f) |
+                                  ((BX_VGA_THIS s.attribute_ctrl.color_select & 0x0c) << 4);
+                      }
+                    // DAC_regno &= video DAC mask register ???
+
+                    BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+                    }
+                  }
+                SET_TILE_UPDATED (xti, yti, 0);
+                bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+                }
+              }
+            }
+          }
+        break; // case 0
+
+      case 1: // output the data in a CGA-compatible 320x200 4 color graphics
+              // mode.  (modes 4 & 5)
+
+        /* CGA 320x200x4 start */
+
+        for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+          for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+            if (GET_TILE_UPDATED (xti, yti)) {
+              for (r=0; r<Y_TILESIZE; r++) {
+                y = yc + r;
+                if (BX_VGA_THIS s.y_doublescan) y >>= 1;
+                for (c=0; c<X_TILESIZE; c++) {
+
+                  x = xc + c;
+                  if (BX_VGA_THIS s.x_dotclockdiv2) x >>= 1;
+                  /* 0 or 0x2000 */
+                  byte_offset = start_addr + ((y & 1) << 13);
+                  /* to the start of the line */
+                  byte_offset += (320 / 4) * (y / 2);
+                  /* to the byte start */
+                  byte_offset += (x / 4);
+
+                  attribute = 6 - 2*(x % 4);
+                  palette_reg_val = (BX_VGA_THIS s.vga_memory[byte_offset]) >> attribute;
+                  palette_reg_val &= 3;
+                  DAC_regno = BX_VGA_THIS s.attribute_ctrl.palette_reg[palette_reg_val];
+                  BX_VGA_THIS s.tile[r*X_TILESIZE + c] = DAC_regno;
+                }
+              }
+              SET_TILE_UPDATED (xti, yti, 0);
+              bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+            }
+          }
+        }
+        /* CGA 320x200x4 end */
+
+        break; // case 1
+
+      case 2: // output the data eight bits at a time from the 4 bit plane
+              // (format for VGA mode 13 hex)
+
+        if ( BX_VGA_THIS s.sequencer.chain_four ) {
+          unsigned long pixely, pixelx, plane;
+          // bx_vga_dump_status();
+
+          if (BX_VGA_THIS s.misc_output.select_high_bank != 1)
+            BX_PANIC(("update: select_high_bank != 1"));
+
+          for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+            for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+              if (GET_TILE_UPDATED (xti, yti)) {
+                for (r=0; r<Y_TILESIZE; r++) {
+                  pixely = yc + r;
+                  if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
+                  for (c=0; c<X_TILESIZE; c++) {
+                    pixelx = (xc + c) >> 1;
+                    plane  = (pixelx % 4);
+                    byte_offset = start_addr + (plane * 65536) +
+                                  (pixely * BX_VGA_THIS s.line_offset) + (pixelx & ~0x03);
+                    color = BX_VGA_THIS s.vga_memory[byte_offset];
+                    BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
+                    }
+                  }
+                SET_TILE_UPDATED (xti, yti, 0);
+                bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+                }
+              }
+            }
+          }
+
+        else { // chain_four == 0, modeX
+          unsigned long pixely, pixelx, plane;
+
+          for (yc=0, yti=0; yc<iHeight; yc+=Y_TILESIZE, yti++) {
+            for (xc=0, xti=0; xc<iWidth; xc+=X_TILESIZE, xti++) {
+              if (GET_TILE_UPDATED (xti, yti)) {
+                for (r=0; r<Y_TILESIZE; r++) {
+                  pixely = yc + r;
+                  if (BX_VGA_THIS s.y_doublescan) pixely >>= 1;
+                  for (c=0; c<X_TILESIZE; c++) {
+                    pixelx = (xc + c) >> 1;
+                    plane  = (pixelx % 4);
+                    byte_offset = (plane * 65536) +
+                                  (pixely * BX_VGA_THIS s.line_offset)
+                                  + (pixelx >> 2);
+                    color = BX_VGA_THIS s.vga_memory[start_addr + byte_offset];
+                    BX_VGA_THIS s.tile[r*X_TILESIZE + c] = color;
+                    }
+                  }
+                SET_TILE_UPDATED (xti, yti, 0);
+                bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc);
+                }
+             }
+           }
+          }
+        break; // case 2
+
+      default:
+        BX_PANIC(("update: shift_reg == %u", (unsigned)
+          BX_VGA_THIS s.graphics_ctrl.shift_reg ));
+      }
+
+    BX_VGA_THIS s.vga_mem_updated = 0;
+    return;
+    }
+
+  else { // text mode
+    unsigned long start_address;
+    unsigned long cursor_address, cursor_x, cursor_y;
+    bx_vga_tminfo_t tm_info;
+
+
+    tm_info.cs_start = BX_VGA_THIS s.CRTC.reg[0x0a] & 0x3f;
+    tm_info.cs_end = BX_VGA_THIS s.CRTC.reg[0x0b] & 0x1f;
+    tm_info.line_offset = BX_VGA_THIS s.CRTC.reg[0x13] << 2;
+    tm_info.line_compare = BX_VGA_THIS s.line_compare;
+    tm_info.h_panning = BX_VGA_THIS s.attribute_ctrl.horiz_pel_panning & 0x0f;
+    tm_info.v_panning = BX_VGA_THIS s.CRTC.reg[0x08] & 0x1f;
+    tm_info.line_graphics = BX_VGA_THIS s.attribute_ctrl.mode_ctrl.enable_line_graphics;
+    if ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 0) {
+      if (tm_info.h_panning == 8)
+        tm_info.h_panning = 0;
+      else
+        tm_info.h_panning++;
+    }
+
+    switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+      case 0: // 128K @ A0000
+      case 1: // 64K @ A0000
+       iWidth = 8*80;  // TODO: should use font size
+       iHeight = 16*25;
+       if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (old_BPP > 8) )
+       {
+         bx_gui->dimension_update(iWidth, iHeight, 16, 8);
+         old_iWidth = iWidth;
+         old_iHeight = iHeight;
+          old_BPP = 8;
+       }
+        /* pass old text snapshot & new VGA memory contents */
+        start_address = 0x0;
+        cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) |
+                          BX_VGA_THIS s.CRTC.reg[0x0f]);
+        if (cursor_address < start_address) {
+          cursor_x = 0xffff;
+          cursor_y = 0xffff;
+          }
+        else {
+          cursor_x = ((cursor_address - start_address)/2) % 80;
+          cursor_y = ((cursor_address - start_address)/2) / 80;
+          }
+        bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
+                          &BX_VGA_THIS s.vga_memory[start_address],
+                           cursor_x, cursor_y, tm_info, 25);
+        // screen updated, copy new VGA memory contents into text snapshot
+        memcpy(BX_VGA_THIS s.text_snapshot,
+              &BX_VGA_THIS s.vga_memory[start_address],
+               2*80*25);
+        BX_VGA_THIS s.vga_mem_updated = 0;
+        break;
+
+      case 2: // B0000 .. B7FFF
+      case 3: // B8000 .. BFFFF
+        unsigned VDE, MSL, rows, cWidth;
+
+        // Verticle Display End: find out how many lines are displayed
+        VDE = BX_VGA_THIS s.vertical_display_end;
+        // Maximum Scan Line: height of character cell
+        MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
+        if (MSL == 0) {
+          //BX_ERROR(("character height = 1, skipping text update"));
+          return;
+        }
+        if ((MSL == 1) && (BX_VGA_THIS s.CRTC.reg[0x06] == 100)) {
+          // emulated CGA graphics mode 160x100x16 colors
+          MSL = 3;
+          rows = 100;
+          cWidth = 8;
+          iWidth = cWidth * BX_VGA_THIS s.CRTC.reg[1];
+          iHeight = 400;
+        } else {
+          rows = (VDE+1)/(MSL+1);
+          if (rows > BX_MAX_TEXT_LINES)
+            BX_PANIC(("text rows>%d: %d",BX_MAX_TEXT_LINES,rows));
+          cWidth = ((BX_VGA_THIS s.sequencer.reg1 & 0x01) == 1) ? 8 : 9;
+          iWidth = cWidth * (BX_VGA_THIS s.CRTC.reg[1] + 1);
+          iHeight = VDE+1;
+        }
+       if( (iWidth != old_iWidth) || (iHeight != old_iHeight) || (MSL != old_MSL) || (old_BPP > 8) )
+       {
+         bx_gui->dimension_update(iWidth, iHeight, MSL+1, cWidth);
+         old_iWidth = iWidth;
+         old_iHeight = iHeight;
+         old_MSL = MSL;
+          old_BPP = 8;
+       }
+        // pass old text snapshot & new VGA memory contents
+        start_address = 2*((BX_VGA_THIS s.CRTC.reg[12] << 8) + BX_VGA_THIS s.CRTC.reg[13]);
+        cursor_address = 2*((BX_VGA_THIS s.CRTC.reg[0x0e] << 8) |
+                          BX_VGA_THIS s.CRTC.reg[0x0f]);
+        if (cursor_address < start_address) {
+          cursor_x = 0xffff;
+          cursor_y = 0xffff;
+          }
+        else {
+          cursor_x = ((cursor_address - start_address)/2) % (iWidth/cWidth);
+          cursor_y = ((cursor_address - start_address)/2) / (iWidth/cWidth);
+          }
+        bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
+                          &BX_VGA_THIS s.vga_memory[start_address],
+                           cursor_x, cursor_y, tm_info, rows);
+        // screen updated, copy new VGA memory contents into text snapshot
+        memcpy(BX_VGA_THIS s.text_snapshot,
+              &BX_VGA_THIS s.vga_memory[start_address],
+               2*80*rows);
+        BX_VGA_THIS s.vga_mem_updated = 0;
+        break;
+      default:
+        BX_DEBUG(("update(): color text mode: mem map is %u",
+                 (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+      }
+    }
+}
+
+
+  Bit8u
+bx_vga_c::mem_read(Bit32u addr)
+{
+  Bit32u offset;
+
+#if BX_SUPPORT_VBE  
+  // if in a vbe enabled mode, read from the vbe_memory
+  if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+  {
+        return vbe_mem_read(addr);
+  }
+#endif  
+
+#if defined(VGA_TRACE_FEATURE)
+//     BX_DEBUG(("8-bit memory read from %08x", addr));
+#endif
+
+#ifdef __OS2__
+
+#if BX_PLUGINS
+#error Fix the code for plugins
+#endif
+
+  if ( bx_options.videomode == BX_VIDEO_DIRECT )
+     {
+     char value;
+
+     value = devices->mem->video[addr-0xA0000];
+
+     return value;
+     }
+#endif
+
+  switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+    case 1: // 0xA0000 .. 0xAFFFF
+      if (addr > 0xAFFFF) return 0xff;
+      offset = addr - 0xA0000;
+      break;
+    case 2: // 0xB0000 .. 0xB7FFF
+      if ((addr < 0xB0000) || (addr > 0xB7FFF)) return 0xff;
+      return BX_VGA_THIS s.vga_memory[addr - 0xB0000];
+      break;
+    case 3: // 0xB8000 .. 0xBFFFF
+      if (addr < 0xB8000) return 0xff;
+      return BX_VGA_THIS s.vga_memory[addr - 0xB8000];
+      break;
+    default: // 0xA0000 .. 0xBFFFF
+      return BX_VGA_THIS s.vga_memory[addr - 0xA0000];
+    }
+
+  // addr between 0xA0000 and 0xAFFFF
+  if ( BX_VGA_THIS s.sequencer.chain_four ) {
+
+    // Mode 13h: 320 x 200 256 color mode: chained pixel representation
+    return BX_VGA_THIS s.vga_memory[(offset & ~0x03) + (offset % 4)*65536];
+    }
+
+  /* addr between 0xA0000 and 0xAFFFF */
+  switch (BX_VGA_THIS s.graphics_ctrl.read_mode) {
+    case 0: /* read mode 0 */
+      BX_VGA_THIS s.graphics_ctrl.latch[0] = BX_VGA_THIS s.vga_memory[          offset];
+      BX_VGA_THIS s.graphics_ctrl.latch[1] = BX_VGA_THIS s.vga_memory[1*65536 + offset];
+      BX_VGA_THIS s.graphics_ctrl.latch[2] = BX_VGA_THIS s.vga_memory[2*65536 + offset];
+      BX_VGA_THIS s.graphics_ctrl.latch[3] = BX_VGA_THIS s.vga_memory[3*65536 + offset];
+      return(BX_VGA_THIS s.graphics_ctrl.latch[BX_VGA_THIS s.graphics_ctrl.read_map_select]);
+      break;
+
+    case 1: /* read mode 1 */
+      {
+      Bit8u color_compare, color_dont_care;
+      Bit8u latch0, latch1, latch2, latch3, retval;
+
+      color_compare   = BX_VGA_THIS s.graphics_ctrl.color_compare & 0x0f;
+      color_dont_care = BX_VGA_THIS s.graphics_ctrl.color_dont_care & 0x0f;
+      latch0 = BX_VGA_THIS s.graphics_ctrl.latch[0] = BX_VGA_THIS s.vga_memory[          offset];
+      latch1 = BX_VGA_THIS s.graphics_ctrl.latch[1] = BX_VGA_THIS s.vga_memory[1*65536 + offset];
+      latch2 = BX_VGA_THIS s.graphics_ctrl.latch[2] = BX_VGA_THIS s.vga_memory[2*65536 + offset];
+      latch3 = BX_VGA_THIS s.graphics_ctrl.latch[3] = BX_VGA_THIS s.vga_memory[3*65536 + offset];
+
+      latch0 ^= ccdat[color_compare][0];
+      latch1 ^= ccdat[color_compare][1];
+      latch2 ^= ccdat[color_compare][2];
+      latch3 ^= ccdat[color_compare][3];
+
+      latch0 &= ccdat[color_dont_care][0];
+      latch1 &= ccdat[color_dont_care][1];
+      latch2 &= ccdat[color_dont_care][2];
+      latch3 &= ccdat[color_dont_care][3];
+
+      retval = ~(latch0 | latch1 | latch2 | latch3);
+
+      return retval;
+      }
+      break;
+    default:
+      return 0;
+    }
+}
+
+  void
+bx_vga_c::mem_write(Bit32u addr, Bit8u value)
+{
+  Bit32u offset;
+  Bit8u new_val[4];
+  unsigned start_addr;
+
+#if BX_SUPPORT_VBE
+  // if in a vbe enabled mode, write to the vbe_memory
+  if ((BX_VGA_THIS s.vbe_enabled) && (BX_VGA_THIS s.vbe_bpp != VBE_DISPI_BPP_4))
+  {
+        vbe_mem_write(addr,value);
+        return;
+  }
+#endif
+
+#if defined(VGA_TRACE_FEATURE)
+//     BX_DEBUG(("8-bit memory write to %08x = %02x", addr, value));
+#endif
+
+#ifdef __OS2__
+
+#if BX_PLUGINS
+#error Fix the code for plugins
+#endif
+
+  if ( bx_options.videomode == BX_VIDEO_DIRECT )
+    {
+    devices->mem->video[addr-0xA0000] = value;
+
+    return;
+    }
+#endif
+
+  switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+    case 1: // 0xA0000 .. 0xAFFFF
+      if (addr > 0xAFFFF) return;
+      offset = addr - 0xA0000;
+      break;
+    case 2: // 0xB0000 .. 0xB7FFF
+      if ((addr < 0xB0000) || (addr > 0xB7FFF)) return;
+      offset = addr - 0xB0000;
+      break;
+    case 3: // 0xB8000 .. 0xBFFFF
+      if (addr < 0xB8000) return;
+      offset = addr - 0xB8000;
+      break;
+    default: // 0xA0000 .. 0xBFFFF
+      offset = addr - 0xA0000;
+    }
+
+  start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d];
+
+  if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+    if (BX_VGA_THIS s.graphics_ctrl.memory_mapping == 3) { // 0xB8000 .. 0xBFFFF
+      unsigned x_tileno, x_tileno2, y_tileno;
+
+      /* CGA 320x200x4 / 640x200x2 start */
+      BX_VGA_THIS s.vga_memory[offset] = value;
+      offset -= start_addr;
+      if (offset>=0x2000) {
+        y_tileno = offset - 0x2000;
+        y_tileno /= (320/4);
+        y_tileno <<= 1; //2 * y_tileno;
+        y_tileno++;
+        x_tileno = (offset - 0x2000) % (320/4);
+        x_tileno <<= 2; //*= 4;
+      } else {
+        y_tileno = offset / (320/4);
+        y_tileno <<= 1; //2 * y_tileno;
+        x_tileno = offset % (320/4);
+        x_tileno <<= 2; //*=4;
+      }
+      x_tileno2=x_tileno;
+      if (BX_VGA_THIS s.graphics_ctrl.shift_reg==0) {
+        x_tileno*=2;
+        x_tileno2+=7;
+      } else {
+        x_tileno2+=3;
+      }
+      if (BX_VGA_THIS s.x_dotclockdiv2) {
+        x_tileno/=(X_TILESIZE/2);
+        x_tileno2/=(X_TILESIZE/2);
+      } else {
+        x_tileno/=X_TILESIZE;
+        x_tileno2/=X_TILESIZE;
+      }
+      if (BX_VGA_THIS s.y_doublescan) {
+        y_tileno/=(Y_TILESIZE/2);
+      } else {
+        y_tileno/=Y_TILESIZE;
+      }
+      BX_VGA_THIS s.vga_mem_updated = 1;
+      SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+      if (x_tileno2!=x_tileno) {
+        SET_TILE_UPDATED (x_tileno2, y_tileno, 1);
+      }
+      return;
+      /* CGA 320x200x4 / 640x200x2 end */
+      }
+    else if (BX_VGA_THIS s.graphics_ctrl.memory_mapping != 1) {
+
+      BX_PANIC(("mem_write: graphics: mapping = %u",
+               (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+      return;
+      }
+
+    if ( BX_VGA_THIS s.sequencer.chain_four ) {
+      unsigned x_tileno, y_tileno;
+
+      // 320 x 200 256 color mode: chained pixel representation
+      BX_VGA_THIS s.vga_memory[(offset & ~0x03) + (offset % 4)*65536] = value;
+      offset -= start_addr;
+      x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE/2);
+      if (BX_VGA_THIS s.y_doublescan) {
+        y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE/2);
+      } else {
+        y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+      }
+      BX_VGA_THIS s.vga_mem_updated = 1;
+      SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+      return;
+      }
+
+    }
+
+  /* addr between 0xA0000 and 0xAFFFF */
+  switch (BX_VGA_THIS s.graphics_ctrl.write_mode) {
+    unsigned i;
+
+    case 0: /* write mode 0 */
+      {
+        const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
+        const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
+        const Bit8u enable_set_reset = BX_VGA_THIS s.graphics_ctrl.enable_set_reset;
+        /* perform rotate on CPU data in case its needed */
+        if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
+          value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
+                  (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
+        }
+        new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+        new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+        new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+        new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+        switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+          case 0: // replace
+            new_val[0] |= ((enable_set_reset & 1)
+                           ? ((set_reset & 1) ? bitmask : 0)
+                           : (value & bitmask));
+            new_val[1] |= ((enable_set_reset & 2)
+                           ? ((set_reset & 2) ? bitmask : 0)
+                           : (value & bitmask));
+            new_val[2] |= ((enable_set_reset & 4)
+                           ? ((set_reset & 4) ? bitmask : 0)
+                           : (value & bitmask));
+            new_val[3] |= ((enable_set_reset & 8)
+                           ? ((set_reset & 8) ? bitmask : 0)
+                           : (value & bitmask));
+            break;
+          case 1: // AND
+            new_val[0] |= ((enable_set_reset & 1)
+                           ? ((set_reset & 1)
+                              ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+                              : 0)
+                           : (value & BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
+            new_val[1] |= ((enable_set_reset & 2)
+                           ? ((set_reset & 2)
+                              ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+                              : 0)
+                           : (value & BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
+            new_val[2] |= ((enable_set_reset & 4)
+                           ? ((set_reset & 4)
+                              ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+                              : 0)
+                           : (value & BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
+            new_val[3] |= ((enable_set_reset & 8)
+                           ? ((set_reset & 8)
+                              ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+                              : 0)
+                           : (value & BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
+            break;
+          case 2: // OR
+            new_val[0]
+              |= ((enable_set_reset & 1)
+                  ? ((set_reset & 1)
+                     ? bitmask
+                     : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
+                  : ((value | BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask));
+            new_val[1]
+              |= ((enable_set_reset & 2)
+                  ? ((set_reset & 2)
+                     ? bitmask
+                     : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
+                  : ((value | BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask));
+            new_val[2]
+              |= ((enable_set_reset & 4)
+                  ? ((set_reset & 4)
+                     ? bitmask
+                     : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
+                  : ((value | BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask));
+            new_val[3]
+              |= ((enable_set_reset & 8)
+                  ? ((set_reset & 8)
+                     ? bitmask
+                     : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
+                  : ((value | BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask));
+            break;
+          case 3: // XOR
+            new_val[0]
+              |= ((enable_set_reset & 1)
+                 ? ((set_reset & 1)
+                    ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+                    : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask))
+                 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[0]) & bitmask);
+            new_val[1]
+              |= ((enable_set_reset & 2)
+                 ? ((set_reset & 2)
+                    ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+                    : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask))
+                 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[1]) & bitmask);
+            new_val[2]
+              |= ((enable_set_reset & 4)
+                 ? ((set_reset & 4)
+                    ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+                    : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask))
+                 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[2]) & bitmask);
+            new_val[3]
+              |= ((enable_set_reset & 8)
+                 ? ((set_reset & 8)
+                    ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+                    : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask))
+                 : (value ^ BX_VGA_THIS s.graphics_ctrl.latch[3]) & bitmask);
+            break;
+          default:
+            BX_PANIC(("vga_mem_write: write mode 0: op = %u",
+                      (unsigned) BX_VGA_THIS s.graphics_ctrl.raster_op));
+        }
+      }
+      break;
+
+    case 1: /* write mode 1 */
+      for (i=0; i<4; i++ ) {
+        new_val[i] = BX_VGA_THIS s.graphics_ctrl.latch[i];
+        }
+      break;
+
+    case 2: /* write mode 2 */
+      {
+        const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask;
+
+        new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+        new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+        new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+        new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+        switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+          case 0: // write
+            new_val[0] |= (value & 1) ? bitmask : 0;
+            new_val[1] |= (value & 2) ? bitmask : 0;
+            new_val[2] |= (value & 4) ? bitmask : 0;
+            new_val[3] |= (value & 8) ? bitmask : 0;
+            break;
+          case 1: // AND
+            new_val[0] |= (value & 1)
+              ? (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+              : 0;
+            new_val[1] |= (value & 2)
+              ? (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+              : 0;
+            new_val[2] |= (value & 4)
+              ? (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+              : 0;
+            new_val[3] |= (value & 8)
+              ? (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+              : 0;
+            break;
+          case 2: // OR
+            new_val[0] |= (value & 1)
+              ? bitmask
+              : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
+            new_val[1] |= (value & 2)
+              ? bitmask
+              : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
+            new_val[2] |= (value & 4)
+              ? bitmask
+              : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
+            new_val[3] |= (value & 8)
+              ? bitmask
+              : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
+            break;
+          case 3: // XOR
+            new_val[0] |= (value & 1)
+              ? (~BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask)
+              : (BX_VGA_THIS s.graphics_ctrl.latch[0] & bitmask);
+            new_val[1] |= (value & 2)
+              ? (~BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask)
+              : (BX_VGA_THIS s.graphics_ctrl.latch[1] & bitmask);
+            new_val[2] |= (value & 4)
+              ? (~BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask)
+              : (BX_VGA_THIS s.graphics_ctrl.latch[2] & bitmask);
+            new_val[3] |= (value & 8)
+              ? (~BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask)
+              : (BX_VGA_THIS s.graphics_ctrl.latch[3] & bitmask);
+            break;
+        }
+      }
+      break;
+
+    case 3: /* write mode 3 */
+      {
+        const Bit8u bitmask = BX_VGA_THIS s.graphics_ctrl.bitmask & value;
+        const Bit8u set_reset = BX_VGA_THIS s.graphics_ctrl.set_reset;
+
+        /* perform rotate on CPU data */
+        if (BX_VGA_THIS s.graphics_ctrl.data_rotate) {
+          value = (value >> BX_VGA_THIS s.graphics_ctrl.data_rotate) |
+                  (value << (8 - BX_VGA_THIS s.graphics_ctrl.data_rotate));
+        }
+        new_val[0] = BX_VGA_THIS s.graphics_ctrl.latch[0] & ~bitmask;
+        new_val[1] = BX_VGA_THIS s.graphics_ctrl.latch[1] & ~bitmask;
+        new_val[2] = BX_VGA_THIS s.graphics_ctrl.latch[2] & ~bitmask;
+        new_val[3] = BX_VGA_THIS s.graphics_ctrl.latch[3] & ~bitmask;
+
+        value &= bitmask;
+
+        switch (BX_VGA_THIS s.graphics_ctrl.raster_op) {
+          case 0: // write
+            new_val[0] |= (set_reset & 1) ? value : 0;
+            new_val[1] |= (set_reset & 2) ? value : 0;
+            new_val[2] |= (set_reset & 4) ? value : 0;
+            new_val[3] |= (set_reset & 8) ? value : 0;
+            break;
+          case 1: // AND
+            new_val[0] |= ((set_reset & 1) ? value : 0)
+              & BX_VGA_THIS s.graphics_ctrl.latch[0];
+            new_val[1] |= ((set_reset & 2) ? value : 0)
+              & BX_VGA_THIS s.graphics_ctrl.latch[1];
+            new_val[2] |= ((set_reset & 4) ? value : 0)
+              & BX_VGA_THIS s.graphics_ctrl.latch[2];
+            new_val[3] |= ((set_reset & 8) ? value : 0)
+              & BX_VGA_THIS s.graphics_ctrl.latch[3];
+            break;
+          case 2: // OR
+            new_val[0] |= ((set_reset & 1) ? value : 0)
+              | BX_VGA_THIS s.graphics_ctrl.latch[0];
+            new_val[1] |= ((set_reset & 2) ? value : 0)
+              | BX_VGA_THIS s.graphics_ctrl.latch[1];
+            new_val[2] |= ((set_reset & 4) ? value : 0)
+              | BX_VGA_THIS s.graphics_ctrl.latch[2];
+            new_val[3] |= ((set_reset & 8) ? value : 0)
+              | BX_VGA_THIS s.graphics_ctrl.latch[3];
+            break;
+          case 3: // XOR
+            new_val[0] |= ((set_reset & 1) ? value : 0)
+              ^ BX_VGA_THIS s.graphics_ctrl.latch[0];
+            new_val[1] |= ((set_reset & 2) ? value : 0)
+              ^ BX_VGA_THIS s.graphics_ctrl.latch[1];
+            new_val[2] |= ((set_reset & 4) ? value : 0)
+              ^ BX_VGA_THIS s.graphics_ctrl.latch[2];
+            new_val[3] |= ((set_reset & 8) ? value : 0)
+              ^ BX_VGA_THIS s.graphics_ctrl.latch[3];
+            break;
+        }
+      }
+      break;
+
+    default:
+      BX_PANIC(("vga_mem_write: write mode %u ?",
+        (unsigned) BX_VGA_THIS s.graphics_ctrl.write_mode));
+  }
+
+  if (BX_VGA_THIS s.sequencer.map_mask & 0x0f) {
+    BX_VGA_THIS s.vga_mem_updated = 1;
+    if (BX_VGA_THIS s.sequencer.map_mask_bit[0])
+      BX_VGA_THIS s.vga_memory[0*65536 + offset] = new_val[0];
+    if (BX_VGA_THIS s.sequencer.map_mask_bit[1])
+      BX_VGA_THIS s.vga_memory[1*65536 + offset] = new_val[1];
+    if (BX_VGA_THIS s.sequencer.map_mask_bit[2]) {
+      if ((!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) &&
+          ((offset & 0xe000) == BX_VGA_THIS s.charmap_address)) {
+        bx_gui->set_text_charbyte((offset & 0x1fff), new_val[2]);
+        }
+      BX_VGA_THIS s.vga_memory[2*65536 + offset] = new_val[2];
+      }
+    if (BX_VGA_THIS s.sequencer.map_mask_bit[3])
+      BX_VGA_THIS s.vga_memory[3*65536 + offset] = new_val[3];
+
+    unsigned x_tileno, y_tileno;
+
+    if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) {
+      offset -= start_addr;
+      x_tileno = (offset % BX_VGA_THIS s.line_offset) * 4 / (X_TILESIZE / 2);
+      if (BX_VGA_THIS s.y_doublescan) {
+        y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
+      } else {
+        y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+      }
+      SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+    } else {
+      if (BX_VGA_THIS s.line_compare < BX_VGA_THIS s.vertical_display_end) {
+        if (BX_VGA_THIS s.x_dotclockdiv2) {
+          x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
+        } else {
+          x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
+        }
+        if (BX_VGA_THIS s.y_doublescan) {
+          y_tileno = ((offset / BX_VGA_THIS s.line_offset) * 2 + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
+        } else {
+          y_tileno = ((offset / BX_VGA_THIS s.line_offset) + BX_VGA_THIS s.line_compare + 1) / Y_TILESIZE;
+        }
+        SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+      }
+      if (offset >= start_addr) {
+        offset -= start_addr;
+        if (BX_VGA_THIS s.x_dotclockdiv2) {
+          x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 16);
+        } else {
+          x_tileno = (offset % BX_VGA_THIS s.line_offset) / (X_TILESIZE / 8);
+        }
+        if (BX_VGA_THIS s.y_doublescan) {
+          y_tileno = (offset / BX_VGA_THIS s.line_offset) / (Y_TILESIZE / 2);
+        } else {
+          y_tileno = (offset / BX_VGA_THIS s.line_offset) / Y_TILESIZE;
+        }
+        SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+      }
+    }
+  }
+}
+
+  void
+bx_vga_c::get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
+                                                   unsigned *txWidth)
+{
+  unsigned VDE, MSL;
+
+  if (!BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+    *text_snapshot = &BX_VGA_THIS s.text_snapshot[0];
+    VDE = BX_VGA_THIS s.vertical_display_end;
+    MSL = BX_VGA_THIS s.CRTC.reg[0x09] & 0x1f;
+    *txHeight = (VDE+1)/(MSL+1);
+    *txWidth = BX_VGA_THIS s.CRTC.reg[1] + 1;
+  } else {
+    *txHeight = 0;
+    *txWidth = 0;
+  }
+}
+
+  Bit8u
+bx_vga_c::get_actl_palette_idx(Bit8u index)
+{
+  return BX_VGA_THIS s.attribute_ctrl.palette_reg[index];
+}
+
+  void
+bx_vga_c::dump_status(void)
+{
+  BX_INFO(("s.misc_output.color_emulation = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.color_emulation));
+  BX_INFO(("s.misc_output.enable_ram = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.enable_ram));
+  BX_INFO(("s.misc_output.clock_select = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.clock_select));
+  if (BX_VGA_THIS s.misc_output.clock_select == 0)
+    BX_INFO(("  25Mhz 640 horiz pixel clock"));
+  else
+    BX_INFO(("  28Mhz 720 horiz pixel clock"));
+  BX_INFO(("s.misc_output.select_high_bank = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.select_high_bank));
+  BX_INFO(("s.misc_output.horiz_sync_pol = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.horiz_sync_pol));
+  BX_INFO(("s.misc_output.vert_sync_pol = %u",
+            (unsigned) BX_VGA_THIS s.misc_output.vert_sync_pol));
+  switch ( (BX_VGA_THIS s.misc_output.vert_sync_pol << 1) |
+           BX_VGA_THIS s.misc_output.horiz_sync_pol ) {
+    case 0: BX_INFO(("  (reserved")); break;
+    case 1: BX_INFO(("  400 lines")); break;
+    case 2: BX_INFO(("  350 lines")); break;
+    case 3: BX_INFO(("  480 lines")); break;
+    default: BX_INFO(("  ???"));
+    }
+
+  BX_INFO(("s.graphics_ctrl.odd_even = %u",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.odd_even));
+  BX_INFO(("s.graphics_ctrl.chain_odd_even = %u",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.chain_odd_even));
+  BX_INFO(("s.graphics_ctrl.shift_reg = %u",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.shift_reg));
+  BX_INFO(("s.graphics_ctrl.graphics_alpha = %u",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.graphics_alpha));
+  BX_INFO(("s.graphics_ctrl.memory_mapping = %u",
+            (unsigned) BX_VGA_THIS s.graphics_ctrl.memory_mapping));
+  switch (BX_VGA_THIS s.graphics_ctrl.memory_mapping) {
+    case 0: BX_INFO(("  A0000-BFFFF")); break;
+    case 1: BX_INFO(("  A0000-AFFFF")); break;
+    case 2: BX_INFO(("  B0000-B7FFF")); break;
+    case 3: BX_INFO(("  B8000-BFFFF")); break;
+    default: BX_INFO(("  ???"));
+    }
+
+  BX_INFO(("s.sequencer.extended_mem = %u",
+            (unsigned) BX_VGA_THIS s.sequencer.extended_mem));
+  BX_INFO(("s.sequencer.odd_even = %u (inverted)",
+            (unsigned) BX_VGA_THIS s.sequencer.odd_even));
+  BX_INFO(("s.sequencer.chain_four = %u",
+            (unsigned) BX_VGA_THIS s.sequencer.chain_four));
+
+  BX_INFO(("s.attribute_ctrl.video_enabled = %u",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.video_enabled));
+  BX_INFO(("s.attribute_ctrl.mode_ctrl.graphics_alpha = %u",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha));
+  BX_INFO(("s.attribute_ctrl.mode_ctrl.display_type = %u",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.display_type));
+  BX_INFO(("s.attribute_ctrl.mode_ctrl.internal_palette_size = %u",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.internal_palette_size));
+  BX_INFO(("s.attribute_ctrl.mode_ctrl.pixel_clock_select = %u",
+            (unsigned) BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select));
+}
+
+
+  void
+bx_vga_c::redraw_area(unsigned x0, unsigned y0, unsigned width,
+                      unsigned height)
+{
+  unsigned xi, yi, x1, y1, xmax, ymax;
+
+  BX_VGA_THIS s.vga_mem_updated = 1;
+
+#if BX_SUPPORT_VBE
+  if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha || BX_VGA_THIS s.vbe_enabled) {
+#else
+  if (BX_VGA_THIS s.graphics_ctrl.graphics_alpha) {
+#endif
+    // graphics mode
+    x1 = x0 + width  - 1;
+    y1 = y0 + height - 1;
+
+    xmax = old_iWidth;
+    ymax = old_iHeight;
+#if BX_SUPPORT_VBE
+    if (BX_VGA_THIS s.vbe_enabled) {
+      xmax = BX_VGA_THIS s.vbe_xres;
+      ymax = BX_VGA_THIS s.vbe_yres;
+    }
+#endif
+    for (yi=0; yi<ymax; yi+=Y_TILESIZE) {
+      for (xi=0; xi<xmax; xi+=X_TILESIZE) {
+        // is redraw rectangle outside x boundaries of this tile?
+        if (x1 < xi) continue;
+        if (x0 > (xi+X_TILESIZE-1)) continue;
+
+        // is redraw rectangle outside y boundaries of this tile?
+        if (y1 < yi) continue;
+        if (y0 > (yi+Y_TILESIZE-1)) continue;
+       unsigned xti = xi/X_TILESIZE;
+       unsigned yti = yi/Y_TILESIZE;
+        SET_TILE_UPDATED (xti, yti, 1);
+        }
+      }
+    }
+  else {
+    // text mode
+    memset(BX_VGA_THIS s.text_snapshot, 0,
+           sizeof(BX_VGA_THIS s.text_snapshot));
+    }
+}
+
+
+#if BX_SUPPORT_VBE
+  Bit8u  BX_CPP_AttrRegparmN(1)
+bx_vga_c::vbe_mem_read(Bit32u addr)
+{
+  Bit32u offset;
+
+  if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+  {
+    // LFB read
+    offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+  }
+  else
+  {
+    // banked mode read
+    offset = BX_VGA_THIS s.vbe_bank*65536 + addr - 0xA0000;
+  }
+
+  // check for out of memory read
+  if (offset > VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
+    return 0;
+
+  return (BX_VGA_THIS s.vbe_memory[offset]);
+}
+
+  void BX_CPP_AttrRegparmN(2)
+bx_vga_c::vbe_mem_write(Bit32u addr, Bit8u value)
+{
+  Bit32u offset;
+  unsigned x_tileno, y_tileno;
+
+  if (BX_VGA_THIS s.vbe_lfb_enabled)
+  {
+    if (addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+    {
+      // LFB write
+      offset = addr - VBE_DISPI_LFB_PHYSICAL_ADDRESS;
+    }
+    else
+    {
+      // banked mode write while in LFB mode -> ignore
+      return;
+    }
+  }
+  else
+  {
+    if (addr < VBE_DISPI_LFB_PHYSICAL_ADDRESS)
+    {
+      // banked mode write
+      offset = (BX_VGA_THIS s.vbe_bank*65536) + (addr - 0xA0000);
+    }
+    else
+    {
+      // LFB write while in banked mode -> ignore
+      return;
+    }
+  }
+
+  // check for out of memory write
+  if (offset < VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)
+  {
+    BX_VGA_THIS s.vbe_memory[offset]=value;
+  }
+  else
+  {
+    // make sure we don't flood the logfile
+    static int count=0;
+    if (count<100)
+    {
+      count ++;
+      BX_INFO(("VBE_mem_write out of video memory write at %x",offset));
+    }
+  }
+
+  offset-=BX_VGA_THIS s.vbe_virtual_start;
+
+  // only update the UI when writing 'onscreen'
+  if (offset < BX_VGA_THIS s.vbe_visable_screen_size)
+  {
+    y_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) / BX_VGA_THIS s.vbe_virtual_xres) / Y_TILESIZE;
+    x_tileno = ((offset / BX_VGA_THIS s.vbe_bpp_multiplier) % BX_VGA_THIS s.vbe_virtual_xres) / X_TILESIZE;
+
+    if ((y_tileno < BX_NUM_Y_TILES) && (x_tileno < BX_NUM_X_TILES))
+    {
+      BX_VGA_THIS s.vga_mem_updated = 1;
+      SET_TILE_UPDATED (x_tileno, y_tileno, 1);
+    }
+  }  
+}
+
+  Bit32u
+bx_vga_c::vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  return( class_ptr->vbe_read(address, io_len) );
+}
+
+
+  Bit32u
+bx_vga_c::vbe_read(Bit32u address, unsigned io_len)
+{
+#else
+  UNUSED(this_ptr);
+#endif  // !BX_USE_VGA_SMF
+
+//  BX_INFO(("VBE_read %x (len %x)", address, io_len));
+
+  if ((address==VBE_DISPI_IOPORT_INDEX) ||
+      (address==VBE_DISPI_IOPORT_INDEX_OLD))
+  {
+    // index register
+    return (Bit32u) BX_VGA_THIS s.vbe_curindex;
+  }
+  else
+  {
+    // data register read
+    
+    switch (BX_VGA_THIS s.vbe_curindex)
+    {
+      case VBE_DISPI_INDEX_ID: // Display Interface ID check
+      {
+        return BX_VGA_THIS s.vbe_cur_dispi;
+      } break;
+      
+      case VBE_DISPI_INDEX_XRES: // x resolution
+      {
+        return BX_VGA_THIS s.vbe_xres;
+      } break;
+
+      case VBE_DISPI_INDEX_YRES: // y resolution
+      {
+        return BX_VGA_THIS s.vbe_yres;
+      } break;
+      
+      case VBE_DISPI_INDEX_BPP: // bpp
+      {
+        return BX_VGA_THIS s.vbe_bpp;
+      } break;
+
+      case VBE_DISPI_INDEX_ENABLE: // vbe enabled
+      {
+        return BX_VGA_THIS s.vbe_enabled;
+      } break;
+      
+      case VBE_DISPI_INDEX_BANK: // current bank
+      {
+        return BX_VGA_THIS s.vbe_bank;
+      } break;
+
+      case VBE_DISPI_INDEX_X_OFFSET:
+      {
+       return BX_VGA_THIS s.vbe_offset_x;
+      } break;
+
+      case VBE_DISPI_INDEX_Y_OFFSET:
+      {
+       return BX_VGA_THIS s.vbe_offset_y;
+      } break;
+
+      case VBE_DISPI_INDEX_VIRT_WIDTH:
+      {
+       return BX_VGA_THIS s.vbe_virtual_xres;
+       
+      } break;
+      
+      case VBE_DISPI_INDEX_VIRT_HEIGHT:
+      {
+       return BX_VGA_THIS s.vbe_virtual_yres;          
+      } break;
+        
+
+      default:
+      {
+        BX_PANIC(("VBE unknown data read index 0x%x",BX_VGA_THIS s.vbe_curindex));
+      } break;
+    }      
+  }
+  BX_PANIC(("VBE_read shouldn't reach this"));
+  return 0; /* keep compiler happy */
+}
+
+  void
+bx_vga_c::vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
+{
+#if !BX_USE_VGA_SMF
+  bx_vga_c *class_ptr = (bx_vga_c *) this_ptr;
+
+  class_ptr->vbe_write(address, value, io_len);
+}
+
+  Bit32u
+bx_vga_c::vbe_write(Bit32u address, Bit32u value, unsigned io_len)
+{ 
+#else
+  UNUSED(this_ptr);
+#endif  
+
+//  BX_INFO(("VBE_write %x = %x (len %x)", address, value, io_len));
+  
+  switch(address)
+  {
+    // index register    
+    case VBE_DISPI_IOPORT_INDEX:
+    // legacy index register    
+    case VBE_DISPI_IOPORT_INDEX_OLD:
+
+      BX_VGA_THIS s.vbe_curindex = (Bit16u) value;
+      break;
+
+    // data register
+    // FIXME: maybe do some 'sanity' checks on received data?
+    case VBE_DISPI_IOPORT_DATA:
+    // legacy data register
+    case VBE_DISPI_IOPORT_DATA_OLD:
+      switch (BX_VGA_THIS s.vbe_curindex)
+      {
+        case VBE_DISPI_INDEX_ID: // Display Interface ID check
+        {
+          if ( (value == VBE_DISPI_ID0) ||
+               (value == VBE_DISPI_ID1) ||
+               (value == VBE_DISPI_ID2) )
+          {
+            // allow backwards compatible with previous dispi bioses
+            BX_VGA_THIS s.vbe_cur_dispi=value;
+          }
+          else
+          {
+            BX_PANIC(("VBE unknown Display Interface %x",value));
+          }
+
+          // make sure we don't flood the logfile
+          static int count=0;
+          if (count < 100)
+          {
+            count++;
+            BX_INFO(("VBE known Display Interface %x",value));
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_XRES: // set xres
+        {
+          // check that we don't set xres during vbe enabled
+          if (!BX_VGA_THIS s.vbe_enabled)
+          {
+            // check for within max xres range
+            if (value <= VBE_DISPI_MAX_XRES)
+            {
+              BX_VGA_THIS s.vbe_xres=(Bit16u) value;
+              BX_INFO(("VBE set xres (%d)",value));
+            }
+            else
+            {
+              BX_INFO(("VBE set xres more then max xres (%d)",value));
+            }
+          }
+          else
+          {
+            BX_INFO(("VBE set xres during vbe enabled!"));
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_YRES: // set yres
+        {
+          // check that we don't set yres during vbe enabled
+          if (!BX_VGA_THIS s.vbe_enabled)
+          {
+            // check for within max yres range
+            if (value <= VBE_DISPI_MAX_YRES)
+            {
+              BX_VGA_THIS s.vbe_yres=(Bit16u) value;
+              BX_INFO(("VBE set yres (%d)",value));
+            }
+            else
+            {
+              BX_INFO(("VBE set yres more then max yres (%d)",value));
+            }
+          }
+          else
+          {
+            BX_INFO(("VBE set yres during vbe enabled!"));
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_BPP: // set bpp
+        {
+          // check that we don't set bpp during vbe enabled
+          if (!BX_VGA_THIS s.vbe_enabled)
+          {
+            // for backward compatiblity
+            if (value == 0) value = VBE_DISPI_BPP_8;
+            // check for correct bpp range
+            if ((value == VBE_DISPI_BPP_4) || (value == VBE_DISPI_BPP_8) || (value == VBE_DISPI_BPP_15) ||
+                (value == VBE_DISPI_BPP_16) || (value == VBE_DISPI_BPP_24) || (value == VBE_DISPI_BPP_32))
+            {
+              BX_VGA_THIS s.vbe_bpp=(Bit16u) value;
+              BX_INFO(("VBE set bpp (%d)",value));
+            }
+            else
+            {
+              BX_INFO(("VBE set bpp with unknown bpp (%d)",value));
+            }
+          }
+          else
+          {
+            BX_INFO(("VBE set bpp during vbe enabled!"));
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_BANK: // set bank
+        {
+          value=value & 0xff ; // FIXME lobyte = vbe bank A?
+
+          // check for max bank nr
+          if (value < (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB /64))
+          {
+            if (!BX_VGA_THIS s.vbe_lfb_enabled)
+            {
+              BX_DEBUG(("VBE set bank to %d", value));
+              BX_VGA_THIS s.vbe_bank=value;
+            }
+            else
+            {
+              BX_ERROR(("VBE set bank in LFB mode ignored"));
+            }
+          }
+          else
+          {
+            BX_INFO(("VBE set invalid bank (%d)",value));
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_ENABLE: // enable video
+        {
+          if (value & VBE_DISPI_ENABLED)
+          {
+            unsigned depth=0;
+
+            // setup virtual resolution to be the same as current reso      
+            BX_VGA_THIS s.vbe_virtual_yres=BX_VGA_THIS s.vbe_yres;
+            BX_VGA_THIS s.vbe_virtual_xres=BX_VGA_THIS s.vbe_xres;
+
+            // reset offset
+            BX_VGA_THIS s.vbe_offset_x=0;
+            BX_VGA_THIS s.vbe_offset_y=0;
+            BX_VGA_THIS s.vbe_virtual_start=0;
+
+            switch((BX_VGA_THIS s.vbe_bpp))
+            {
+              // Default pixel sizes
+              case VBE_DISPI_BPP_8: 
+                BX_VGA_THIS s.vbe_bpp_multiplier = 1;
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres));
+                depth=8;
+                break;
+
+              case VBE_DISPI_BPP_4: 
+                BX_VGA_THIS s.vbe_bpp_multiplier = 1;
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres));
+                depth=4;
+                break;
+
+              case VBE_DISPI_BPP_15:
+                BX_VGA_THIS s.vbe_bpp_multiplier = 2; 
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 2;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 2;
+                depth=15;
+                break;                   
+
+              case VBE_DISPI_BPP_16:
+                BX_VGA_THIS s.vbe_bpp_multiplier = 2; 
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 2;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 2;
+                depth=16;
+                break;                   
+
+              case VBE_DISPI_BPP_24: 
+                BX_VGA_THIS s.vbe_bpp_multiplier = 3; 
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres * 3;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) * 3;
+                depth=24;
+                break;                   
+
+              case VBE_DISPI_BPP_32: 
+                BX_VGA_THIS s.vbe_bpp_multiplier = 4; 
+                BX_VGA_THIS s.vbe_line_byte_width = BX_VGA_THIS s.vbe_virtual_xres << 2;
+                BX_VGA_THIS s.vbe_visable_screen_size = ((BX_VGA_THIS s.vbe_xres) * (BX_VGA_THIS s.vbe_yres)) << 2;
+                depth=32;
+                break;                   
+            }
+
+            BX_INFO(("VBE enabling x %d, y %d, bpp %d, %u bytes visible", BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, BX_VGA_THIS s.vbe_bpp, BX_VGA_THIS s.vbe_visable_screen_size));
+
+            if (depth > 4)
+            {
+              BX_VGA_THIS s.vbe_lfb_enabled=(bx_bool)(value & VBE_DISPI_LFB_ENABLED);
+              if ((value & VBE_DISPI_NOCLEARMEM) == 0)
+              {
+                memset(BX_VGA_THIS s.vbe_memory, 0, BX_VGA_THIS s.vbe_visable_screen_size);
+              }
+              bx_gui->dimension_update(BX_VGA_THIS s.vbe_xres, BX_VGA_THIS s.vbe_yres, 0, 0, depth);
+              old_BPP = depth;
+              // some test applications expect these standard VGA settings
+              BX_VGA_THIS s.CRTC.reg[9] = 0x00;
+              BX_VGA_THIS s.attribute_ctrl.mode_ctrl.graphics_alpha = 1;
+              BX_VGA_THIS s.graphics_ctrl.memory_mapping = 1;
+              BX_VGA_THIS s.CRTC.reg[1] = (BX_VGA_THIS s.vbe_xres / 8) - 1;
+              BX_VGA_THIS s.CRTC.reg[19] = BX_VGA_THIS s.vbe_xres >> 2;
+              BX_VGA_THIS s.attribute_ctrl.mode_ctrl.pixel_clock_select = 1;
+              BX_VGA_THIS s.CRTC.reg[18] = (BX_VGA_THIS s.vbe_yres - 1) & 0xff;
+              BX_VGA_THIS s.CRTC.reg[7] &= ~0x42;
+              if ((BX_VGA_THIS s.vbe_yres - 1) & 0x0100) {
+                BX_VGA_THIS s.CRTC.reg[7] |= 0x02;
+              }
+              if ((BX_VGA_THIS s.vbe_yres - 1) & 0x0200) {
+                BX_VGA_THIS s.CRTC.reg[7] |= 0x40;
+              }
+            }
+          }
+          else
+          {
+            if (BX_VGA_THIS s.vbe_enabled) BX_INFO(("VBE disabling"));
+            BX_VGA_THIS s.vbe_lfb_enabled=0;
+          }     
+          BX_VGA_THIS s.vbe_enabled=(bx_bool)(value & VBE_DISPI_ENABLED);
+        } break;
+
+        case VBE_DISPI_INDEX_X_OFFSET:
+        {
+          // BX_INFO(("VBE offset x %x",value));
+          BX_VGA_THIS s.vbe_offset_x=(Bit16u)value;
+
+          BX_VGA_THIS s.vbe_virtual_start = ((BX_VGA_THIS s.vbe_offset_y) * (BX_VGA_THIS s.vbe_line_byte_width)) +
+                                             ((BX_VGA_THIS s.vbe_offset_x) * (BX_VGA_THIS s.vbe_bpp_multiplier));
+
+          BX_VGA_THIS s.vga_mem_updated = 1;
+          for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+            for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+              SET_TILE_UPDATED (xti, yti, 1);
+            }
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_Y_OFFSET:
+        {
+          // BX_INFO(("VBE offset y %x",value));
+          BX_VGA_THIS s.vbe_offset_y=(Bit16u)value;
+          BX_VGA_THIS s.vbe_virtual_start = ((BX_VGA_THIS s.vbe_offset_y) * (BX_VGA_THIS s.vbe_line_byte_width)) +
+                                             ((BX_VGA_THIS s.vbe_offset_x) * (BX_VGA_THIS s.vbe_bpp_multiplier));
+
+          BX_VGA_THIS s.vga_mem_updated = 1;
+          for (unsigned xti = 0; xti < BX_NUM_X_TILES; xti++) {
+            for (unsigned yti = 0; yti < BX_NUM_Y_TILES; yti++) {
+              SET_TILE_UPDATED (xti, yti, 1);
+            }
+          }
+        } break;
+
+        case VBE_DISPI_INDEX_VIRT_WIDTH:
+        {
+          BX_INFO(("VBE requested virtual width %d",value));
+
+          // calculate virtual width & height dimensions
+          // req:
+          //   virt_width > xres
+          //   virt_height >=yres
+          //   virt_width*virt_height < MAX_VIDEO_MEMORY
+
+          // basicly 2 situations
+
+          // situation 1: 
+          //   MAX_VIDEO_MEMORY / virt_width >= yres
+          //        adjust result height
+          //   else
+          //        adjust result width based upon virt_height=yres
+          Bit16u new_width=value;
+          Bit16u new_height=(sizeof(BX_VGA_THIS s.vbe_memory) / BX_VGA_THIS s.vbe_bpp_multiplier) / new_width;
+          if (new_height >=BX_VGA_THIS s.vbe_yres)
+          {
+            // we have a decent virtual width & new_height
+            BX_INFO(("VBE decent virtual height %d",new_height));
+          }
+          else
+          {
+            // no decent virtual height: adjust width & height
+            new_height=BX_VGA_THIS s.vbe_yres;
+            new_width=(sizeof(BX_VGA_THIS s.vbe_memory) / BX_VGA_THIS s.vbe_bpp_multiplier) / new_height;
+
+            BX_INFO(("VBE recalc virtual width %d height %d",new_width, new_height));
+          }
+
+          BX_VGA_THIS s.vbe_virtual_xres=new_width;
+          BX_VGA_THIS s.vbe_virtual_yres=new_height;
+          BX_VGA_THIS s.vbe_visable_screen_size = (new_width * (BX_VGA_THIS s.vbe_yres)) * BX_VGA_THIS s.vbe_bpp_multiplier;
+
+        } break;
+       /*      
+        case VBE_DISPI_INDEX_VIRT_HEIGHT:
+        {
+          BX_INFO(("VBE virtual height %x",value));
+
+        } break;
+       */  
+        default:
+        {
+          BX_PANIC(("VBE unknown data write index 0x%x",BX_VGA_THIS s.vbe_curindex));
+        } break;      
+      }        
+      break;
+         
+  } // end switch address
+}
+
+#endif
diff --git a/tools/ioemu/iodev/vga.h b/tools/ioemu/iodev/vga.h
new file mode 100644 (file)
index 0000000..cafb60c
--- /dev/null
@@ -0,0 +1,300 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: vga.h,v 1.36 2003/12/31 10:33:27 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+#if BX_SUPPORT_VBE
+  #define VBE_DISPI_TOTAL_VIDEO_MEMORY_MB 4
+
+  #define VBE_DISPI_BANK_ADDRESS          0xA0000
+  #define VBE_DISPI_BANK_SIZE_KB          64
+
+  #define VBE_DISPI_MAX_XRES              1024
+  #define VBE_DISPI_MAX_YRES              768
+
+  #define VBE_DISPI_IOPORT_INDEX          0x01CE
+  #define VBE_DISPI_IOPORT_DATA           0x01CF
+
+  #define VBE_DISPI_IOPORT_INDEX_OLD      0xFF80
+  #define VBE_DISPI_IOPORT_DATA_OLD       0xFF81
+
+  #define VBE_DISPI_INDEX_ID              0x0
+  #define VBE_DISPI_INDEX_XRES            0x1
+  #define VBE_DISPI_INDEX_YRES            0x2
+  #define VBE_DISPI_INDEX_BPP             0x3
+  #define VBE_DISPI_INDEX_ENABLE          0x4
+  #define VBE_DISPI_INDEX_BANK            0x5
+  #define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+  #define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+  #define VBE_DISPI_INDEX_X_OFFSET        0x8
+  #define VBE_DISPI_INDEX_Y_OFFSET        0x9
+
+  #define VBE_DISPI_ID0                   0xB0C0
+  #define VBE_DISPI_ID1                   0xB0C1
+  #define VBE_DISPI_ID2                   0xB0C2
+
+  #define VBE_DISPI_BPP_4                 0x04
+  #define VBE_DISPI_BPP_8                 0x08
+  #define VBE_DISPI_BPP_15                0x0F
+  #define VBE_DISPI_BPP_16                0x10
+  #define VBE_DISPI_BPP_24                0x18
+  #define VBE_DISPI_BPP_32                0x20
+
+  #define VBE_DISPI_DISABLED              0x00
+  #define VBE_DISPI_ENABLED               0x01
+  #define VBE_DISPI_NOCLEARMEM            0x80
+  #define VBE_DISPI_LFB_ENABLED           0x40
+
+  #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+  
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_KB                (VBE_DISPI_TOTAL_VIDEO_MEMORY_MB * 1024)  
+#define VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES     (VBE_DISPI_TOTAL_VIDEO_MEMORY_KB * 1024)  
+
+#define BX_MAX_XRES VBE_DISPI_MAX_XRES
+#define BX_MAX_YRES VBE_DISPI_MAX_YRES
+
+#else
+
+#define BX_MAX_XRES 800
+#define BX_MAX_YRES 600
+
+#endif //BX_SUPPORT_VBE
+
+#define X_TILESIZE 16
+#define Y_TILESIZE 24
+#define BX_NUM_X_TILES (BX_MAX_XRES /X_TILESIZE)
+#define BX_NUM_Y_TILES (BX_MAX_YRES /Y_TILESIZE)
+
+// Support varying number of rows of text.  This used to
+// be limited to only 25 lines.
+#define BX_MAX_TEXT_LINES 100
+
+#if BX_USE_VGA_SMF
+#  define BX_VGA_SMF  static
+#  define BX_VGA_THIS theVga->
+#else
+#  define BX_VGA_SMF
+#  define BX_VGA_THIS this->
+#endif
+
+
+class bx_vga_c : public bx_vga_stub_c {
+public:
+
+  bx_vga_c(void);
+  ~bx_vga_c(void);
+  virtual void   init(void);
+  virtual void  bios_init(void);
+  virtual void   reset(unsigned type);
+  virtual Bit8u  mem_read(Bit32u addr);
+  // Note: either leave value of type Bit8u, or mask it when
+  //       used to 8 bits, in memory.cc
+  virtual void   mem_write(Bit32u addr, Bit8u value);
+  virtual void   trigger_timer(void *this_ptr);
+
+#if BX_SUPPORT_VBE
+  BX_VGA_SMF Bit8u  vbe_mem_read(Bit32u addr) BX_CPP_AttrRegparmN(1);
+  BX_VGA_SMF void   vbe_mem_write(Bit32u addr, Bit8u value) BX_CPP_AttrRegparmN(2);
+#endif
+
+  virtual void   redraw_area(unsigned x0, unsigned y0,
+                             unsigned width, unsigned height);
+
+  virtual void   set_update_interval (unsigned interval);
+  virtual void   get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight,
+                                   unsigned *txWidth);
+  virtual Bit8u  get_actl_palette_idx(Bit8u index);
+
+private:
+
+  static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+  static void   write_handler_no_log(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+
+#if BX_SUPPORT_VBE
+  static Bit32u vbe_read_handler(void *this_ptr, Bit32u address, unsigned io_len);
+  static void   vbe_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
+#endif
+
+  struct {
+    struct {
+      bx_bool color_emulation;  // 1=color emulation, base address = 3Dx
+                                // 0=mono emulation,  base address = 3Bx
+      bx_bool enable_ram;       // enable CPU access to video memory if set
+      Bit8u   clock_select;     // 0=25Mhz 1=28Mhz
+      bx_bool select_high_bank; // when in odd/even modes, select
+                                // high 64k bank if set
+      bx_bool horiz_sync_pol;   // bit6: negative if set
+      bx_bool vert_sync_pol;    // bit7: negative if set
+                                //   bit7,bit6 represent number of lines on display:
+                                //   0 = reserved
+                                //   1 = 400 lines
+                                //   2 = 350 lines
+                                //   3 - 480 lines
+      } misc_output;
+
+    struct {
+      Bit8u   address;
+      Bit8u   reg[0x19];
+      } CRTC;
+
+    struct {
+      bx_bool  flip_flop; /* 0 = address, 1 = data-write */
+      unsigned address;  /* register number */
+      bx_bool  video_enabled;
+      Bit8u    palette_reg[16];
+      Bit8u    overscan_color;
+      Bit8u    color_plane_enable;
+      Bit8u    horiz_pel_panning;
+      Bit8u    color_select;
+      struct {
+        bx_bool graphics_alpha;
+        bx_bool display_type;
+        bx_bool enable_line_graphics;
+        bx_bool blink_intensity;
+        bx_bool pixel_panning_compat;
+        bx_bool pixel_clock_select;
+        bx_bool internal_palette_size;
+        } mode_ctrl;
+      } attribute_ctrl;
+
+    struct {
+      Bit8u write_data_register;
+      Bit8u write_data_cycle; /* 0, 1, 2 */
+      Bit8u read_data_register;
+      Bit8u read_data_cycle; /* 0, 1, 2 */
+      Bit8u dac_state;
+      struct {
+        Bit8u red;
+        Bit8u green;
+        Bit8u blue;
+        } data[256];
+      Bit8u mask;
+      } pel;
+
+
+    struct {
+      Bit8u   index;
+      Bit8u   set_reset;
+      Bit8u   enable_set_reset;
+      Bit8u   color_compare;
+      Bit8u   data_rotate;
+      Bit8u   raster_op;
+      Bit8u   read_map_select;
+      Bit8u   write_mode;
+      bx_bool read_mode;
+      bx_bool odd_even;
+      bx_bool chain_odd_even;
+      Bit8u   shift_reg;
+      bx_bool graphics_alpha;
+      Bit8u   memory_mapping; /* 0 = use A0000-BFFFF
+                               * 1 = use A0000-AFFFF EGA/VGA graphics modes
+                               * 2 = use B0000-B7FFF Monochrome modes
+                               * 3 = use B8000-BFFFF CGA modes
+                               */
+      Bit8u   color_dont_care;
+      Bit8u   bitmask;
+      Bit8u   latch[4];
+      } graphics_ctrl;
+
+    struct {
+      Bit8u   index;
+      Bit8u   map_mask;
+      bx_bool map_mask_bit[4];
+      bx_bool reset1;
+      bx_bool reset2;
+      Bit8u   reg1;
+      Bit8u   char_map_select;
+      bx_bool extended_mem;
+      bx_bool odd_even;
+      bx_bool chain_four;
+      } sequencer;
+
+    bx_bool  vga_mem_updated;
+    unsigned x_tilesize;
+    unsigned y_tilesize;
+    unsigned line_offset;
+    unsigned line_compare;
+    unsigned vertical_display_end;
+    bx_bool  vga_tile_updated[BX_NUM_X_TILES][BX_NUM_Y_TILES];
+    Bit8u vga_memory[256 * 1024];
+    Bit8u text_snapshot[32 * 1024]; // current text snapshot
+    Bit8u rgb[3 * 256];
+    Bit8u tile[X_TILESIZE * Y_TILESIZE * 4]; /**< Currently allocates the tile as large as needed. */
+    Bit16u charmap_address;
+    bx_bool x_dotclockdiv2;
+    bx_bool y_doublescan;
+
+#if BX_SUPPORT_VBE    
+    Bit8u vbe_memory[VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES];
+    Bit16u  vbe_cur_dispi;
+    Bit16u  vbe_xres;
+    Bit16u  vbe_yres;
+    Bit16u  vbe_bpp;
+    Bit16u  vbe_bank;
+    bx_bool vbe_enabled;
+    Bit16u  vbe_curindex;
+    Bit32u  vbe_visable_screen_size; /**< in bytes */
+    Bit16u  vbe_offset_x;               /**< Virtual screen x start (in pixels) */ 
+    Bit16u  vbe_offset_y;               /**< Virtual screen y start (in pixels) */
+    Bit16u  vbe_virtual_xres;
+    Bit16u  vbe_virtual_yres;
+    Bit16u  vbe_line_byte_width; /**< For dealing with bpp>8, this is they width of a line in bytes. */
+    Bit32u  vbe_virtual_start;   /**< For dealing with bpp>8, this is where the virtual screen starts. */
+    Bit8u   vbe_bpp_multiplier;  /**< We have to save this b/c sometimes we need to recalculate stuff with it. */
+    bx_bool vbe_lfb_enabled;
+#endif    
+    } s;  // state information
+
+
+#if !BX_USE_VGA_SMF
+  Bit32u read(Bit32u address, unsigned io_len);
+  void   write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#else
+  void write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#endif
+
+#if BX_SUPPORT_VBE
+
+#if !BX_USE_VGA_SMF
+  Bit32u vbe_read(Bit32u address, unsigned io_len);
+  void   vbe_write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#else
+  void vbe_write(Bit32u address, Bit32u value, unsigned io_len, bx_bool no_log);
+#endif
+#endif
+
+  int timer_id;
+
+  public:
+  static void   timer_handler(void *);
+  BX_VGA_SMF void   timer(void);
+
+  private:
+  BX_VGA_SMF void   update(void);
+  BX_VGA_SMF void   dump_status(void);
+  BX_VGA_SMF void determine_screen_dimensions(unsigned *piHeight,
+                                              unsigned *piWidth);
+  };
diff --git a/tools/ioemu/iodev/virt_timer.cc b/tools/ioemu/iodev/virt_timer.cc
new file mode 100644 (file)
index 0000000..eb108a0
--- /dev/null
@@ -0,0 +1,552 @@
+////////////////////////////////////////////////////////////////////////
+// $Id: virt_timer.cc,v 1.19.2.1 2004/02/06 22:14:36 danielg4 Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+/////////////////////////////////////////////////////////////////////////
+//
+//Realtime Algorithm (with gettimeofday)
+//  HAVE:
+//    Real number of usec.
+//    Emulated number of usec.
+//  WANT:
+//    Number of ticks to use.
+//    Number of emulated usec to wait until next try.
+//
+//  ticks=number of ticks needed to match total real usec.
+//  if(desired ticks > max ticks for elapsed real time)
+//     ticks = max ticks for elapsed real time.
+//  if(desired ticks > max ticks for elapsed emulated usec)
+//     ticks = max ticks for emulated usec.
+//  next wait ticks = number of ticks until next event.
+//  next wait real usec = (current ticks + next wait ticks) * usec per ticks
+//  next wait emulated usec = next wait real usec * emulated usec / real usec
+//  if(next wait emulated usec < minimum emulated usec for next wait ticks)
+//     next wait emulated usec = minimum emulated usec for next wait ticks.
+//  if(next wait emulated usec > max emulated usec wait)
+//     next wait emulated usec = max emulated usec wait.
+//
+//  How to calculate elapsed real time:
+//    store an unused time value whenever no ticks are used in a given time.
+//    add this to the current elapsed time.
+//  How to calculate elapsed emulated time:
+//    same as above.
+//  Above can be done by not updating last_usec and last_sec.
+//
+//  How to calculate emulated usec/real usec:
+//    Each time there are actual ticks:
+//      Alpha_product(old emulated usec, emulated usec);
+//      Alpha_product(old real usec, real usec);
+//    Divide resulting values.
+//
+/////////////////////////////////////////////////////////////////////////
+
+#include "bochs.h"
+
+#define BX_USE_VIRTUAL_TIMERS 1
+#define BX_VIRTUAL_TIMERS_REALTIME 1
+
+//Important constant #defines:
+#define USEC_PER_SECOND (1000000)
+
+
+// define a macro to convert floating point numbers into 64-bit integers.
+// In MSVC++ you can convert a 64-bit float into a 64-bit signed integer,
+// but it will not convert a 64-bit float into a 64-bit unsigned integer.
+// This macro works around that.
+#define F2I(x)  ((Bit64u)(Bit64s) (x))
+#define I2F(x)  ((double)(Bit64s) (x))
+
+//CONFIGURATION #defines:
+
+
+//MAINLINE Configuration (For realtime PIT):
+
+//How much faster than real time we can go:
+#define MAX_MULT (1.25)
+
+//Minimum number of emulated useconds per second.
+//  Now calculated using BX_MIN_IPS, the minimum number of
+//   instructions per second.
+#define MIN_USEC_PER_SECOND (((((Bit64u)USEC_PER_SECOND)*((Bit64u)BX_MIN_IPS))/((Bit64u)(bx_options.Oips->get())))+(Bit64u)1)
+
+
+//DEBUG configuration:
+
+//Debug with printf options.
+#define DEBUG_REALTIME_WITH_PRINTF 0
+
+//Use to test execution at multiples of real time.
+#define TIME_DIVIDER (1)
+#define TIME_MULTIPLIER (1)
+#define TIME_HEADSTART (0)
+
+
+#define GET_VIRT_REALTIME64_USEC() (((bx_get_realtime64_usec()*(Bit64u)TIME_MULTIPLIER/(Bit64u)TIME_DIVIDER)))
+//Set up Logging.
+#define LOG_THIS bx_virt_timer.
+
+//A single instance.
+bx_virt_timer_c bx_virt_timer;
+
+
+//Generic MAX and MIN Functions
+#define BX_MAX(a,b) ( ((a)>(b))?(a):(b) )
+#define BX_MIN(a,b) ( ((a)>(b))?(b):(a) )
+
+
+//USEC_ALPHA is multiplier for the past.
+//USEC_ALPHA_B is 1-USEC_ALPHA, or multiplier for the present.
+#define USEC_ALPHA ((double)(.8))
+#define USEC_ALPHA_B ((double)(((double)1)-USEC_ALPHA))
+#define USEC_ALPHA2 ((double)(.5))
+#define USEC_ALPHA2_B ((double)(((double)1)-USEC_ALPHA2))
+#define ALPHA_LOWER(old,new) ((Bit64u)((old<new)?((USEC_ALPHA*(I2F(old)))+(USEC_ALPHA_B*(I2F(new)))):((USEC_ALPHA2*(I2F(old)))+(USEC_ALPHA2_B*(I2F(new))))))
+
+
+//Conversion between emulated useconds and optionally realtime ticks.
+#define TICKS_TO_USEC(a) ( ((a)*usec_per_second)/ticks_per_second )
+#define USEC_TO_TICKS(a) ( ((a)*ticks_per_second)/usec_per_second )
+
+bx_virt_timer_c::bx_virt_timer_c( void )
+{
+  put("VTIMER");
+  settype(VTIMERLOG);
+
+  numTimers = 0;
+  current_timers_time = 0;
+  timers_next_event_time = BX_MAX_VIRTUAL_TIME;
+  last_sequential_time = 0;
+  in_timer_handler = 0;
+  virtual_next_event_time = BX_MAX_VIRTUAL_TIME;
+  current_virtual_time = 0;
+
+  use_virtual_timers = BX_USE_VIRTUAL_TIMERS;
+  init_done = 0;
+}
+
+bx_virt_timer_c::~bx_virt_timer_c( void )
+{
+}
+
+
+
+const Bit64u bx_virt_timer_c::NullTimerInterval = BX_MAX_VIRTUAL_TIME;
+
+void
+bx_virt_timer_c::nullTimer(void* this_ptr) {
+  UNUSED(this_ptr);
+}
+
+void
+bx_virt_timer_c::periodic(Bit64u time_passed) {
+  //Assert that we haven't skipped any events.
+  BX_ASSERT (time_passed <= timers_next_event_time);
+  BX_ASSERT(!in_timer_handler);
+
+  //Update time variables.
+  timers_next_event_time -= time_passed;
+  current_timers_time += time_passed;
+
+  //If no events are occurring, just pass the time and we're done.
+  if( time_passed < timers_next_event_time ) {
+    return;
+  }
+  //Starting timer handler calls.
+  in_timer_handler = 1;
+  //Otherwise, cause any events to occur that should.
+  unsigned i;
+  for(i=0;i<numTimers;i++) {
+    if( timer[i].inUse && timer[i].active ) {
+      //Assert that we haven't skipped any timers.
+      BX_ASSERT(current_timers_time <= timer[i].timeToFire);
+      if(timer[i].timeToFire == current_timers_time) {
+       if(timer[i].continuous) {
+         timer[i].timeToFire+=timer[i].period;
+       } else {
+         timer[i].active = 0;
+       }
+       //This function MUST return, or the timer mechanism
+       // will be broken.
+       timer[i].funct(timer[i].this_ptr);
+      }
+    }
+  }
+  //Finished timer handler calls.
+  in_timer_handler = 0;
+  //Use a second FOR loop so that a timer function call can
+  //  change the behavior of another timer.
+  //timers_next_event_time normally contains a cycle count, not a cycle time.
+  //  here we use it as a temporary variable that IS a cycle time,
+  //  but then convert it back to a cycle count afterwards.
+  timers_next_event_time = current_timers_time + BX_MAX_VIRTUAL_TIME;
+  for(i=0;i<numTimers;i++) {
+    if( timer[i].inUse && timer[i].active && ((timer[i].timeToFire)<timers_next_event_time) ) {
+      timers_next_event_time = timer[i].timeToFire;
+    }
+  }
+  timers_next_event_time-=current_timers_time;
+  next_event_time_update();
+  //FIXME
+}
+
+
+//Get the current virtual time.
+//  This may return the same value on subsequent calls.
+Bit64u
+bx_virt_timer_c::time_usec(void) {
+  if(!use_virtual_timers) {
+    return bx_pc_system.time_usec();
+  }
+
+  //Update the time here only if we're not in a timer handler.
+  //If we're in a timer handler we're up-to-date, and otherwise
+  // this prevents call stack loops.
+  if(!in_timer_handler) {
+    timer_handler();
+  }
+
+  return current_timers_time;
+}
+
+//Get the current virtual time.
+//  This will return a monotonically increasing value.
+// MUST NOT be called from within a timer interrupt.
+Bit64u
+bx_virt_timer_c::time_usec_sequential(void) {
+  if(!use_virtual_timers) {
+    return bx_pc_system.time_usec_sequential();
+  }
+
+  //Can't prevent call stack loops here, so this
+  // MUST NOT be called from within a timer handler.
+  BX_ASSERT(timers_next_event_time>0);
+  BX_ASSERT(!in_timer_handler);
+
+  if(last_sequential_time >= current_timers_time) {
+    periodic(1);
+    last_sequential_time = current_timers_time;
+  }
+  return current_timers_time;
+}
+
+
+
+//Register a timer handler to go off after a given interval.
+//Register a timer handler to go off with a periodic interval.
+int
+bx_virt_timer_c::register_timer( void *this_ptr, bx_timer_handler_t handler,
+                                Bit32u useconds,
+                                bx_bool continuous, bx_bool active,
+                                const char *id) {
+  if(!use_virtual_timers) {
+    return bx_pc_system.register_timer(this_ptr, handler, useconds,
+                                      continuous, active, id);
+  }
+
+  //We don't like starting with a zero period timer.
+  BX_ASSERT((!active) || (useconds>0));
+
+  //Search for an unused timer.
+  unsigned int i;
+  for (i=0; i < numTimers; i++) {
+    if (timer[i].inUse == 0 || i==numTimers)
+      break;
+    }
+  // If we didn't find a free slot, increment the bound, numTimers.
+  if (i==numTimers)
+    numTimers++; // One new timer installed.
+  BX_ASSERT(numTimers<BX_MAX_VIRTUAL_TIMERS);
+
+  timer[i].inUse = 1;
+  timer[i].period = useconds;
+  timer[i].timeToFire = current_timers_time + (Bit64u)useconds;
+  timer[i].active = active;
+  timer[i].continuous = continuous;
+  timer[i].funct = handler;
+  timer[i].this_ptr = this_ptr;
+  strncpy(timer[i].id, id, BxMaxTimerIDLen);
+  timer[i].id[BxMaxTimerIDLen-1]=0; //I like null terminated strings.
+
+  if(useconds < timers_next_event_time) {
+    timers_next_event_time = useconds;
+    next_event_time_update();
+    //FIXME
+  }
+  return i;
+}
+
+//unregister a previously registered timer.
+unsigned
+bx_virt_timer_c::unregisterTimer(int timerID) {
+  if(!use_virtual_timers) {
+    return bx_pc_system.unregisterTimer(timerID);
+  }
+
+  BX_ASSERT(timerID >= 0);
+  BX_ASSERT(timerID < BX_MAX_VIRTUAL_TIMERS);
+
+  if (timer[timerID].active) {
+    BX_PANIC(("unregisterTimer: timer '%s' is still active!", timer[timerID].id));
+    return(0); // Fail.
+    }
+
+
+  //No need to prevent doing this to unused timers.
+  timer[timerID].inUse = 0;
+  return(1);
+}
+
+void
+bx_virt_timer_c::start_timers(void) {
+  if(!use_virtual_timers) {
+    bx_pc_system.start_timers();
+    return;
+  }
+  //FIXME
+}
+
+//activate a deactivated but registered timer.
+void
+bx_virt_timer_c::activate_timer( unsigned timer_index, Bit32u useconds,
+                      bx_bool continuous ) {
+  if(!use_virtual_timers) {
+    bx_pc_system.activate_timer(timer_index, useconds, continuous);
+    return;
+  }
+
+  BX_ASSERT(timer_index >= 0);
+  BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
+
+  BX_ASSERT(timer[timer_index].inUse);
+  BX_ASSERT(useconds>0);
+
+  timer[timer_index].period=useconds;
+  timer[timer_index].timeToFire = current_timers_time + (Bit64u)useconds;
+  timer[timer_index].active=1;
+  timer[timer_index].continuous=continuous;
+
+  if(useconds < timers_next_event_time) {
+    timers_next_event_time = useconds;
+    next_event_time_update();
+    //FIXME
+  }
+}
+
+//deactivate (but don't unregister) a currently registered timer.
+void
+bx_virt_timer_c::deactivate_timer( unsigned timer_index ) {
+  if(!use_virtual_timers) {
+    bx_pc_system.deactivate_timer(timer_index);
+    return;
+  }
+
+  BX_ASSERT(timer_index >= 0);
+  BX_ASSERT(timer_index < BX_MAX_VIRTUAL_TIMERS);
+
+  //No need to prevent doing this to unused/inactive timers.
+  timer[timer_index].active = 0;
+}
+
+void
+bx_virt_timer_c::advance_virtual_time(Bit64u time_passed) {
+  BX_ASSERT(time_passed <= virtual_next_event_time);
+
+  current_virtual_time += time_passed;
+  virtual_next_event_time -= time_passed;
+
+  if(current_virtual_time > current_timers_time) {
+    periodic(current_virtual_time - current_timers_time);
+  }
+}
+
+//Called when next_event_time changes.
+void
+bx_virt_timer_c::next_event_time_update(void) {
+  virtual_next_event_time = timers_next_event_time + current_timers_time - current_virtual_time;
+  if(init_done) {
+    bx_pc_system.deactivate_timer(system_timer_id);
+    BX_ASSERT(virtual_next_event_time);
+    bx_pc_system.activate_timer(system_timer_id, 
+                               (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))),
+                               0);
+  }
+}
+
+void
+bx_virt_timer_c::init(void) {
+
+  if ( (bx_options.clock.Osync->get ()!=BX_CLOCK_SYNC_REALTIME)
+    && (bx_options.clock.Osync->get ()!=BX_CLOCK_SYNC_BOTH) )
+    virtual_timers_realtime = 0;
+  else
+    virtual_timers_realtime = 1;
+
+  if (virtual_timers_realtime) {
+    BX_INFO(("using 'realtime pit' synchronization method"));
+  }
+
+  register_timer(this, nullTimer, (Bit32u)NullTimerInterval, 1, 1, "Null Timer");
+
+  system_timer_id = bx_pc_system.register_timer(this, pc_system_timer_handler,virtual_next_event_time , 0, 1, "Virtual Timer");
+
+  //Real time variables:
+#if BX_HAVE_REALTIME_USEC
+  last_real_time=GET_VIRT_REALTIME64_USEC()+(Bit64u)TIME_HEADSTART*(Bit64u)USEC_PER_SECOND;
+#endif
+  total_real_usec=0;
+  last_realtime_delta=0;
+  //System time variables:
+  last_usec = 0
+;
+  usec_per_second = USEC_PER_SECOND;
+  stored_delta=0;
+  last_system_usec=0;
+  em_last_realtime=0;
+  //Virtual timer variables:
+  total_ticks=0;
+  last_realtime_ticks=0;
+  ticks_per_second = USEC_PER_SECOND;
+
+  init_done = 1;
+}
+
+void
+bx_virt_timer_c::timer_handler(void) {
+  if(!virtual_timers_realtime) {
+    Bit64u temp_final_time = bx_pc_system.time_usec();
+    temp_final_time-=current_virtual_time;
+    while(temp_final_time) {
+      if((temp_final_time)>(virtual_next_event_time)) {
+       temp_final_time-=virtual_next_event_time;
+       advance_virtual_time(virtual_next_event_time);
+      } else {
+       advance_virtual_time(temp_final_time);
+       temp_final_time-=temp_final_time;
+      }
+    }
+    bx_pc_system.activate_timer(system_timer_id,
+                               (Bit32u)BX_MIN(0x7FFFFFFF,(virtual_next_event_time>2)?(virtual_next_event_time-2):1),
+                               0);
+    return;
+  }
+
+  Bit64u usec_delta = bx_pc_system.time_usec()-last_usec;
+
+  if (usec_delta) {
+#if BX_HAVE_REALTIME_USEC
+    Bit64u ticks_delta = 0;
+    Bit64u real_time_delta = GET_VIRT_REALTIME64_USEC() - last_real_time;
+    Bit64u real_time_total = real_time_delta + total_real_usec;
+    Bit64u system_time_delta = (Bit64u)usec_delta + (Bit64u)stored_delta;
+    if(real_time_delta) {
+      last_realtime_delta = real_time_delta;
+      last_realtime_ticks = total_ticks;
+    }
+    ticks_per_second = USEC_PER_SECOND;
+
+    //Start out with the number of ticks we would like
+    // to have to line up with real time.
+    ticks_delta = real_time_total - total_ticks;
+    if(real_time_total < total_ticks) {
+      //This slows us down if we're already ahead.
+      //  probably only an issue on startup, but it solves some problems.
+      ticks_delta = 0;
+    }
+    if(ticks_delta + total_ticks - last_realtime_ticks > (F2I(MAX_MULT * I2F(last_realtime_delta)))) {
+      //This keeps us from going too fast in relation to real time.
+#if 0
+      ticks_delta = (F2I(MAX_MULT * I2F(last_realtime_delta))) + last_realtime_ticks - total_ticks;
+#endif
+      ticks_per_second = F2I(MAX_MULT * I2F(USEC_PER_SECOND));
+    }
+    if(ticks_delta > system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND) {
+      //This keeps us from having too few instructions between ticks.
+      ticks_delta = system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND;
+    }
+    if(ticks_delta > virtual_next_event_time) {
+      //This keeps us from missing ticks.
+      ticks_delta = virtual_next_event_time;
+    }
+
+    if(ticks_delta) {
+
+#  if DEBUG_REALTIME_WITH_PRINTF
+      //Every second print some info.
+      if(((last_real_time + real_time_delta) / USEC_PER_SECOND) > (last_real_time / USEC_PER_SECOND)) {
+       Bit64u temp1, temp2, temp3, temp4;
+       temp1 = (Bit64u) total_real_usec;
+       temp2 = (total_real_usec);
+       temp3 = (Bit64u)total_ticks;
+       temp4 = (Bit64u)((total_real_usec) - total_ticks);
+       printf("useconds: %llu, ",temp1);
+       printf("expect ticks: %llu, ",temp2);
+       printf("ticks: %llu, ",temp3);
+       printf("diff: %llu\n",temp4);
+      }
+#  endif
+
+      last_real_time += real_time_delta;
+      total_real_usec += real_time_delta;
+      last_system_usec += system_time_delta;
+      stored_delta = 0;
+      total_ticks += ticks_delta;
+    } else {
+      stored_delta = system_time_delta;
+    }
+
+
+    Bit64u a,b;
+    a=(usec_per_second);
+    if(real_time_delta) {
+      //FIXME
+      Bit64u em_realtime_delta = last_system_usec + stored_delta - em_last_realtime;
+      b=((Bit64u)USEC_PER_SECOND * em_realtime_delta / real_time_delta);
+      em_last_realtime = last_system_usec + stored_delta;
+    } else {
+      b=a;
+    }
+    usec_per_second = ALPHA_LOWER(a,b);
+#else
+    BX_ASSERT(0);
+#endif
+#if BX_HAVE_REALTIME_USEC
+    advance_virtual_time(ticks_delta);
+#endif
+  }
+
+  last_usec=last_usec + usec_delta;
+  bx_pc_system.deactivate_timer(system_timer_id);
+  BX_ASSERT(virtual_next_event_time);
+  bx_pc_system.activate_timer(system_timer_id, 
+                             (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))),
+                             0);
+
+}
+
+void
+bx_virt_timer_c::pc_system_timer_handler(void* this_ptr) {
+  ((bx_virt_timer_c *)this_ptr)->timer_handler();
+}
+
diff --git a/tools/ioemu/iodev/virt_timer.h b/tools/ioemu/iodev/virt_timer.h
new file mode 100644 (file)
index 0000000..a10b16c
--- /dev/null
@@ -0,0 +1,131 @@
+
+#ifndef _BX_VIRT_TIMER_H
+#define _BX_VIRT_TIMER_H
+
+
+#define BX_MAX_VIRTUAL_TIMERS (15+BX_SMP_PROCESSORS)
+#define BX_NULL_VIRTUAL_TIMER_HANDLE 10000
+
+#define BX_MAX_VIRTUAL_TIME (0x7fffffff)
+
+class bx_virt_timer_c : public logfunctions {
+ private:
+
+  struct {
+    bx_bool inUse;      // Timer slot is in-use (currently registered).
+    Bit64u  period;     // Timer periodocity in virtual useconds.
+    Bit64u  timeToFire; // Time to fire next (in virtual useconds).
+    bx_bool active;     // 0=inactive, 1=active.
+    bx_bool continuous; // 0=one-shot timer, 1=continuous periodicity.
+    bx_timer_handler_t funct;  // A callback function for when the
+                               //   timer fires.
+                               //   This function MUST return.
+    void *this_ptr;            // The this-> pointer for C++ callbacks
+                               //   has to be stored as well.
+    char id[BxMaxTimerIDLen]; // String ID of timer.
+  } timer[BX_MAX_VIRTUAL_TIMERS];
+
+  unsigned   numTimers;  // Number of currently allocated timers.
+
+  //Variables for the timer subsystem:
+  Bit64u current_timers_time;
+  Bit64u timers_next_event_time;
+
+  Bit64u last_sequential_time;
+  bx_bool in_timer_handler;
+
+  //Variables for the time sync subsystem:
+  Bit64u virtual_next_event_time;
+  Bit64u current_virtual_time;
+
+  //Real time variables:
+  Bit64u last_real_time;
+  Bit64u total_real_usec;
+  Bit64u last_realtime_delta;
+  //System time variables:
+  Bit64u last_usec;
+  Bit64u usec_per_second;
+  Bit64u stored_delta;
+  Bit64u last_system_usec;
+  Bit64u em_last_realtime;
+  //Virtual timer variables:
+  Bit64u total_ticks;
+  Bit64u last_realtime_ticks;
+  Bit64u ticks_per_second;
+
+  bx_bool init_done;
+
+  int system_timer_id;
+
+  //Whether or not to use virtual timers.
+  bx_bool use_virtual_timers;
+  bx_bool virtual_timers_realtime;
+
+  // A special null timer is always inserted in the timer[0] slot.  This
+  // make sure that at least one timer is always active, and that the
+  // duration is always less than a maximum 32-bit integer, so a 32-bit
+  // counter can be used for the current countdown.
+  static const Bit64u NullTimerInterval;
+  static void nullTimer(void* this_ptr);
+
+
+  //Step the given number of cycles, optionally calling any timer handlers.
+  void periodic(Bit64u time_passed);
+
+
+  //Called when next_event_time changes.
+  void next_event_time_update(void);
+
+  //Called to advance the virtual time.
+  // calls periodic as needed.
+  void advance_virtual_time(Bit64u time_passed);
+
+ public:
+
+
+  //Get the current virtual time.
+  //  This may return the same value on subsequent calls.
+  Bit64u time_usec(void);
+
+  //Get the current virtual time.
+  //  This will return a monotonically increasing value.
+  // MUST NOT be called from within a timer handler.
+  Bit64u time_usec_sequential(void);
+
+  //Register a timer handler to go off after a given interval.
+  //Register a timer handler to go off with a periodic interval.
+  int    register_timer( void *this_ptr, bx_timer_handler_t handler,
+                         Bit32u useconds,
+                         bx_bool continuous, bx_bool active, const char *id);
+
+  //unregister a previously registered timer.
+  unsigned unregisterTimer(int timerID);
+
+  void   start_timers(void);
+
+  //activate a deactivated but registered timer.
+  void   activate_timer( unsigned timer_index, Bit32u useconds,
+                         bx_bool continuous );
+
+  //deactivate (but don't unregister) a currently registered timer.
+  void   deactivate_timer( unsigned timer_index );
+
+
+  //Timer handler passed to pc_system
+  static void pc_system_timer_handler(void* this_ptr);
+
+  //The real timer handler.
+  void timer_handler();
+
+  //Initialization
+  void init(void);
+  bx_virt_timer_c(void);
+  ~bx_virt_timer_c(void);
+
+};
+
+
+
+extern bx_virt_timer_c bx_virt_timer;
+
+#endif // _BX_VIRT_TIMER_H
diff --git a/tools/ioemu/memory/Makefile b/tools/ioemu/memory/Makefile
new file mode 100644 (file)
index 0000000..cd85cb8
--- /dev/null
@@ -0,0 +1,11 @@
+TOPDIR= ..
+CXXFLAGS=-I. -I../include -I..
+OBJS= memory.o misc_mem.o
+
+all: libmemory.a
+
+libmemory.a: $(OBJS)
+       $(AR) $(ARFLAGS) $@ $(OBJS)
+
+include $(TOPDIR)/mk/helix.mk
+
diff --git a/tools/ioemu/memory/memory.cc b/tools/ioemu/memory/memory.cc
new file mode 100644 (file)
index 0000000..7ee55f3
--- /dev/null
@@ -0,0 +1,450 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: memory.cc,v 1.27 2003/03/02 23:59:12 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+
+
+
+#include "bochs.h"
+#define LOG_THIS BX_MEM_THIS
+
+#if BX_PROVIDE_CPU_MEMORY
+
+  void BX_CPP_AttrRegparmN(3)
+BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+  Bit8u *data_ptr;
+  Bit32u a20addr;
+
+  // Note: accesses should always be contained within a single page now.
+
+#if BX_IODEBUG_SUPPORT
+  bx_iodebug_c::mem_write(cpu, addr, len, data);
+#endif
+  if (addr+len > this->dma_limit)
+          BX_PANIC(("address too large: %lx > %lx", addr+len, this->dma_limit));
+
+  a20addr = A20ADDR(addr);
+  BX_INSTR_PHY_WRITE(cpu->which_cpu(), a20addr, len);
+
+#if BX_DEBUGGER
+  // (mch) Check for physical write break points, TODO
+  // (bbd) Each breakpoint should have an associated CPU#, TODO
+  for (int i = 0; i < num_write_watchpoints; i++)
+        if (write_watchpoint[i] == a20addr) {
+             BX_CPU(0)->watchpoint = a20addr;
+              BX_CPU(0)->break_point = BREAK_POINT_WRITE;
+              break;
+        }
+#endif
+
+#if BX_SupportICache
+  if (a20addr < BX_MEM_THIS len)
+    cpu->iCache.decWriteStamp(cpu, a20addr);
+#endif
+
+  if ( a20addr <= BX_MEM_THIS len ) {
+    // all of data is within limits of physical memory
+    if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+      if (len == 4) {
+        WriteHostDWordToLittleEndian(&vector[a20addr], *(Bit32u*)data);
+        BX_DBG_DIRTY_PAGE(a20addr >> 12);
+        return;
+        }
+      if (len == 2) {
+        WriteHostWordToLittleEndian(&vector[a20addr], *(Bit16u*)data);
+        BX_DBG_DIRTY_PAGE(a20addr >> 12);
+        return;
+        }
+      if (len == 1) {
+        * ((Bit8u *) (&vector[a20addr])) = * (Bit8u *) data;
+        BX_DBG_DIRTY_PAGE(a20addr >> 12);
+        return;
+        }
+      // len == other, just fall thru to special cases handling
+      }
+
+#ifdef BX_LITTLE_ENDIAN
+  data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+  data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+write_one:
+    if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+      // addr *not* in range 00080000 .. 000FFFFF
+      vector[a20addr] = *data_ptr;
+      BX_DBG_DIRTY_PAGE(a20addr >> 12);
+inc_one:
+      if (len == 1) return;
+      len--;
+      a20addr++;
+#ifdef BX_LITTLE_ENDIAN
+      data_ptr++;
+#else // BX_BIG_ENDIAN
+      data_ptr--;
+#endif
+      goto write_one;
+      }
+
+    // addr in range 00080000 .. 000FFFFF
+
+    if (a20addr <= 0x0009ffff) {
+      // regular memory 80000 .. 9FFFF
+      vector[a20addr] = *data_ptr;
+      BX_DBG_DIRTY_PAGE(a20addr >> 12);
+      goto inc_one;
+      }
+    if (a20addr <= 0x000bffff) {
+      // VGA memory A0000 .. BFFFF
+      DEV_vga_mem_write(a20addr, *data_ptr);
+      BX_DBG_DIRTY_PAGE(a20addr >> 12);
+      BX_DBG_UCMEM_REPORT(a20addr, 1, BX_WRITE, *data_ptr); // obsolete
+      goto inc_one;
+      }
+    // adapter ROM     C0000 .. DFFFF
+    // ROM BIOS memory E0000 .. FFFFF
+    // (ignore write)
+    //BX_INFO(("ROM lock %08x: len=%u",
+    //  (unsigned) a20addr, (unsigned) len));
+#if BX_PCI_SUPPORT == 0
+#if BX_SHADOW_RAM
+    // Write it since its in shadow RAM
+    vector[a20addr] = *data_ptr;
+    BX_DBG_DIRTY_PAGE(a20addr >> 12);
+#else
+    // ignore write to ROM
+#endif
+#else
+    // Write Based on 440fx Programming
+    if (bx_options.Oi440FXSupport->get () &&
+        ((a20addr >= 0xC0000) && (a20addr <= 0xFFFFF))) {
+      switch (DEV_pci_wr_memtype(a20addr & 0xFC000)) {
+        case 0x1:   // Writes to ShadowRAM
+//        BX_INFO(("Writing to ShadowRAM %08x, len %u ! ", (unsigned) a20addr, (unsigned) len));
+          shadow[a20addr - 0xc0000] = *data_ptr;
+          BX_DBG_DIRTY_PAGE(a20addr >> 12);
+          goto inc_one;
+
+        case 0x0:   // Writes to ROM, Inhibit
+          BX_DEBUG(("Write to ROM ignored: address %08x, data %02x", (unsigned) a20addr, *data_ptr));
+          goto inc_one;
+        default:
+          BX_PANIC(("writePhysicalPage: default case"));
+          goto inc_one;
+        }
+      }
+#endif
+    goto inc_one;
+    }
+
+  else {
+    // some or all of data is outside limits of physical memory
+    unsigned i;
+
+#ifdef BX_LITTLE_ENDIAN
+  data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+  data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+
+#if BX_SUPPORT_VBE
+    // Check VBE LFB support
+    
+    if ((a20addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS) &&
+        (a20addr <  (VBE_DISPI_LFB_PHYSICAL_ADDRESS +  VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)))
+    {
+      for (i = 0; i < len; i++) {
+        
+        //if (a20addr < BX_MEM_THIS len) {
+          //vector[a20addr] = *data_ptr;
+          //BX_DBG_DIRTY_PAGE(a20addr >> 12);
+          DEV_vga_mem_write(a20addr, *data_ptr);
+        //  }
+        
+        // otherwise ignore byte, since it overruns memory
+        addr++;
+        a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+        data_ptr++;
+#else // BX_BIG_ENDIAN
+        data_ptr--;
+#endif
+      }
+      return;
+    }
+    
+#endif    
+
+#if BX_SUPPORT_APIC
+    bx_generic_apic_c *local_apic = &cpu->local_apic;
+    bx_generic_apic_c *ioapic = bx_devices.ioapic;
+    if (local_apic->is_selected (a20addr, len)) {
+      local_apic->write (a20addr, (Bit32u *)data, len);
+      return;
+    } else if (ioapic->is_selected (a20addr, len)) {
+      ioapic->write (a20addr, (Bit32u *)data, len);
+      return;
+    }
+    else 
+#endif
+    for (i = 0; i < len; i++) {
+      if (a20addr < BX_MEM_THIS len) {
+        vector[a20addr] = *data_ptr;
+        BX_DBG_DIRTY_PAGE(a20addr >> 12);
+        }
+      // otherwise ignore byte, since it overruns memory
+      addr++;
+      a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+      data_ptr++;
+#else // BX_BIG_ENDIAN
+      data_ptr--;
+#endif
+      }
+    return;
+    }
+}
+
+
+  void BX_CPP_AttrRegparmN(3)
+BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, Bit32u addr, unsigned len, void *data)
+{
+  Bit8u *data_ptr;
+  Bit32u a20addr;
+
+#if BX_IODEBUG_SUPPORT
+  bx_iodebug_c::mem_read(cpu, addr, len, data);
+#endif
+  
+  if (addr+len > this->dma_limit)
+          BX_PANIC(("address too large: %lx > %lx", addr+len, this->dma_limit));
+
+  a20addr = A20ADDR(addr);
+  BX_INSTR_PHY_READ(cpu->which_cpu(), a20addr, len);
+
+#if BX_DEBUGGER
+  // (mch) Check for physical read break points, TODO
+  // (bbd) Each breakpoint should have an associated CPU#, TODO
+  for (int i = 0; i < num_read_watchpoints; i++)
+        if (read_watchpoint[i] == a20addr) {
+             BX_CPU(0)->watchpoint = a20addr;
+              BX_CPU(0)->break_point = BREAK_POINT_READ;
+              break;
+        }
+#endif
+
+  if ( (a20addr + len) <= BX_MEM_THIS len ) {
+    // all of data is within limits of physical memory
+    if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+      if (len == 4) {
+        ReadHostDWordFromLittleEndian(&vector[a20addr], * (Bit32u*) data);
+        return;
+        }
+      if (len == 2) {
+        ReadHostWordFromLittleEndian(&vector[a20addr], * (Bit16u*) data);
+        return;
+        }
+      if (len == 1) {
+        * (Bit8u *) data =  * ((Bit8u *) (&vector[a20addr]));
+        return;
+        }
+      // len == 3 case can just fall thru to special cases handling
+      }
+
+
+#ifdef BX_LITTLE_ENDIAN
+    data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+    data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+
+
+read_one:
+    if ( (a20addr & 0xfff80000) != 0x00080000 ) {
+      // addr *not* in range 00080000 .. 000FFFFF
+      *data_ptr = vector[a20addr];
+inc_one:
+      if (len == 1) return;
+      len--;
+      a20addr++;
+#ifdef BX_LITTLE_ENDIAN
+      data_ptr++;
+#else // BX_BIG_ENDIAN
+      data_ptr--;
+#endif
+      goto read_one;
+      }
+
+    // addr in range 00080000 .. 000FFFFF
+#if BX_PCI_SUPPORT == 0
+    if ((a20addr <= 0x0009ffff) || (a20addr >= 0x000c0000) ) {
+      // regular memory 80000 .. 9FFFF, C0000 .. F0000
+      *data_ptr = vector[a20addr];
+      goto inc_one;
+      }
+    // VGA memory A0000 .. BFFFF
+    *data_ptr = DEV_vga_mem_read(a20addr);
+    BX_DBG_UCMEM_REPORT(a20addr, 1, BX_READ, *data_ptr); // obsolete
+    goto inc_one;
+#else   // #if BX_PCI_SUPPORT == 0
+    if (a20addr <= 0x0009ffff) {
+      *data_ptr = vector[a20addr];
+      goto inc_one;
+      }
+    if (a20addr <= 0x000BFFFF) {
+      // VGA memory A0000 .. BFFFF
+      *data_ptr = DEV_vga_mem_read(a20addr);
+      BX_DBG_UCMEM_REPORT(a20addr, 1, BX_READ, *data_ptr);
+      goto inc_one;
+      }
+
+    // a20addr in C0000 .. FFFFF
+    if (!bx_options.Oi440FXSupport->get ()) {
+      *data_ptr = vector[a20addr];
+      goto inc_one;
+      }
+    else {
+      switch (DEV_pci_rd_memtype(a20addr & 0xFC000)) {
+        case 0x1:   // Read from ShadowRAM
+          *data_ptr = shadow[a20addr - 0xc0000];
+          BX_INFO(("Reading from ShadowRAM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+          goto inc_one;
+
+        case 0x0:   // Read from ROM
+          *data_ptr = vector[a20addr];
+          //BX_INFO(("Reading from ROM %08x, Data %02x  ", (unsigned) a20addr, *data_ptr));
+          goto inc_one;
+        default:
+          BX_PANIC(("::readPhysicalPage: default case"));
+        }
+      }
+    goto inc_one;
+#endif  // #if BX_PCI_SUPPORT == 0
+    }
+  else {
+    // some or all of data is outside limits of physical memory
+    unsigned i;
+
+#ifdef BX_LITTLE_ENDIAN
+    data_ptr = (Bit8u *) data;
+#else // BX_BIG_ENDIAN
+    data_ptr = (Bit8u *) data + (len - 1);
+#endif
+
+#if BX_SUPPORT_VBE
+    // Check VBE LFB support
+    
+    if ((a20addr >= VBE_DISPI_LFB_PHYSICAL_ADDRESS) &&
+        (a20addr <  (VBE_DISPI_LFB_PHYSICAL_ADDRESS +  VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES)))
+    {
+      for (i = 0; i < len; i++) {
+        
+        //if (a20addr < BX_MEM_THIS len) {
+          //vector[a20addr] = *data_ptr;
+          //BX_DBG_DIRTY_PAGE(a20addr >> 12);
+          *data_ptr = DEV_vga_mem_read(a20addr);
+        //  }
+        
+        // otherwise ignore byte, since it overruns memory
+        addr++;
+        a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+        data_ptr++;
+#else // BX_BIG_ENDIAN
+        data_ptr--;
+#endif
+      }
+      return;
+    }
+    
+#endif    
+
+
+#if BX_SUPPORT_APIC
+    bx_generic_apic_c *local_apic = &cpu->local_apic;
+    bx_generic_apic_c *ioapic = bx_devices.ioapic;
+    if (local_apic->is_selected (addr, len)) {
+      local_apic->read (addr, data, len);
+      return;
+    } else if (ioapic->is_selected (addr, len)) {
+      ioapic->read (addr, data, len);
+      return;
+    }
+#endif
+    for (i = 0; i < len; i++) {
+#if BX_PCI_SUPPORT == 0
+      if (a20addr < BX_MEM_THIS len)
+        *data_ptr = vector[a20addr];
+      else
+        *data_ptr = 0xff;
+#else   // BX_PCI_SUPPORT == 0
+      if (a20addr < BX_MEM_THIS len) {
+        if ((a20addr >= 0x000C0000) && (a20addr <= 0x000FFFFF)) {
+          if (!bx_options.Oi440FXSupport->get ())
+            *data_ptr = vector[a20addr];
+          else {
+            switch (DEV_pci_rd_memtype(a20addr & 0xFC000)) {
+              case 0x0:   // Read from ROM
+                *data_ptr = vector[a20addr];
+                //BX_INFO(("Reading from ROM %08x, Data %02x ", (unsigned) a20addr, *data_ptr));
+                break;
+
+              case 0x1:   // Read from Shadow RAM
+                *data_ptr = shadow[a20addr - 0xc0000];
+                BX_INFO(("Reading from ShadowRAM %08x, Data %02x  ", (unsigned) a20addr, *data_ptr));
+                break;
+              default:
+                BX_PANIC(("readPhysicalPage: default case"));
+              } // Switch
+            }
+          }
+        else {
+          *data_ptr = vector[a20addr];
+          BX_INFO(("Reading from Norm %08x, Data %02x  ", (unsigned) a20addr, *data_ptr));
+          }
+        }
+      else 
+        *data_ptr = 0xff;
+#endif  // BX_PCI_SUPPORT == 0
+      addr++;
+      a20addr = (addr);
+#ifdef BX_LITTLE_ENDIAN
+      data_ptr++;
+#else // BX_BIG_ENDIAN
+      data_ptr--;
+#endif
+      }
+    return;
+    }
+}
+
+#endif // #if BX_PROVIDE_CPU_MEMORY
diff --git a/tools/ioemu/memory/memory.h b/tools/ioemu/memory/memory.h
new file mode 100644 (file)
index 0000000..2af787b
--- /dev/null
@@ -0,0 +1,98 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: memory.h,v 1.16 2003/08/05 13:19:35 cbothamy Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2001  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+#define BX_USE_MEM_SMF 0
+
+#if BX_USE_MEM_SMF
+// if static member functions on, then there is only one memory
+#  define BX_MEM_SMF  static
+#  define BX_MEM_THIS BX_MEM(0)->
+#else
+#  define BX_MEM_SMF
+#  define BX_MEM_THIS this->
+#endif
+
+// alignment of memory vector, must be a power of 2
+#define BX_MEM_VECTOR_ALIGN 4096
+
+class BOCHSAPI BX_MEM_C : public logfunctions {
+
+public:
+  Bit8u   *actual_vector;
+  Bit8u   *vector;  // aligned correctly
+  size_t  len;
+  size_t  dma_limit;
+  size_t  megabytes;  // (len in Megabytes)
+#if BX_PCI_SUPPORT
+  Bit8u   shadow[4*16*4096]; // 256k of memory
+#endif
+#if BX_DEBUGGER
+  unsigned char dbg_dirty_pages[(BX_MAX_DIRTY_PAGE_TABLE_MEGS * 1024 * 1024) / 4096];
+  Bit32u dbg_count_dirty_pages () {
+    return (BX_MAX_DIRTY_PAGE_TABLE_MEGS * 1024 * 1024) / 4096;
+  }
+#endif
+  unsigned long *page_array;   /* for get_pfn_list() */
+
+  BX_MEM_C(void);
+  //BX_MEM_C(size_t memsize);
+  ~BX_MEM_C(void);
+  BX_MEM_SMF void    alloc_vector_aligned (size_t bytes, size_t alignment) BX_CPP_AttrRegparmN(2);
+  BX_MEM_SMF void    init_memory(int memsize);
+  BX_MEM_SMF void    readPhysicalPage(BX_CPU_C *cpu, Bit32u addr,
+                                      unsigned len, void *data) BX_CPP_AttrRegparmN(3);
+  BX_MEM_SMF void    writePhysicalPage(BX_CPU_C *cpu, Bit32u addr,
+                                       unsigned len, void *data) BX_CPP_AttrRegparmN(3);
+  BX_MEM_SMF void    load_ROM(const char *path, Bit32u romaddress, Bit8u type);
+  BX_MEM_SMF Bit32u  get_memory_in_k(void);
+#if BX_PCI_SUPPORT
+  BX_MEM_SMF Bit8u*  pci_fetch_ptr(Bit32u addr) BX_CPP_AttrRegparmN(1);
+#endif
+  BX_MEM_SMF bx_bool dbg_fetch_mem(Bit32u addr, unsigned len, Bit8u *buf);
+  BX_MEM_SMF bx_bool dbg_set_mem(Bit32u addr, unsigned len, Bit8u *buf);
+  BX_MEM_SMF bx_bool dbg_crc32(
+    unsigned long (*f)(unsigned char *buf, int len),
+    Bit32u addr1, Bit32u addr2, Bit32u *crc);
+  BX_MEM_SMF Bit8u * getHostMemAddr(BX_CPU_C *cpu, Bit32u a20Addr, unsigned op) BX_CPP_AttrRegparmN(3);
+  };
+
+#if BX_PROVIDE_CPU_MEMORY==1
+
+#if BX_SMP_PROCESSORS==1
+BOCHSAPI extern BX_MEM_C    bx_mem;
+#else
+BOCHSAPI extern BX_MEM_C    *bx_mem_array[BX_ADDRESS_SPACES];
+#endif  /* BX_SMP_PROCESSORS */
+
+#endif  /* BX_PROVIDE_CPU_MEMORY==1 */
+
+#if BX_DEBUGGER
+#  define BX_DBG_DIRTY_PAGE(page) BX_MEM(0)->dbg_dirty_pages[page] = 1;
+#else
+#  define BX_DBG_DIRTY_PAGE(page)
+#endif
diff --git a/tools/ioemu/memory/misc_mem.cc b/tools/ioemu/memory/misc_mem.cc
new file mode 100644 (file)
index 0000000..0c883eb
--- /dev/null
@@ -0,0 +1,447 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: misc_mem.cc,v 1.41 2003/09/10 16:34:56 vruppert Exp $
+/////////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2002  MandrakeSoft S.A.
+//
+//    MandrakeSoft S.A.
+//    43, rue d'Aboukir
+//    75002 Paris - France
+//    http://www.linux-mandrake.com/
+//    http://www.mandrakesoft.com/
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2 of the License, or (at your option) any later version.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+
+
+
+
+
+
+#include "bochs.h"
+#ifdef BX_USE_VMX
+extern "C" {
+#include <sys/mman.h>
+}
+#endif
+
+#define LOG_THIS BX_MEM(0)->
+
+#if BX_PROVIDE_CPU_MEMORY
+  Bit32u
+BX_MEM_C::get_memory_in_k(void)
+{
+  return(BX_MEM_THIS megabytes * 1024);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+  // BX_MEM_C constructor
+BX_MEM_C::BX_MEM_C(void)
+{
+  char mem[6];
+  snprintf(mem, 6, "MEM%d", BX_SIM_ID);
+  put(mem);
+  settype(MEMLOG);
+
+  vector = NULL;
+  actual_vector = NULL;
+  len    = 0;
+  megabytes = 0;
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+
+#if BX_PROVIDE_CPU_MEMORY
+void BX_CPP_AttrRegparmN(2)
+BX_MEM_C::alloc_vector_aligned (size_t bytes, size_t alignment)
+{
+  if (actual_vector != NULL) {
+    BX_INFO (("freeing existing memory vector"));
+    delete [] actual_vector;
+    actual_vector = NULL;
+    vector = NULL;
+  }
+  Bit64u test_mask = alignment - 1;
+  actual_vector = new Bit8u [bytes+test_mask];
+  // round address forward to nearest multiple of alignment.  Alignment 
+  // MUST BE a power of two for this to work.
+  Bit64u masked = ((Bit64u)(actual_vector + test_mask)) & ~test_mask;
+  vector = (Bit8u *)masked;
+  // sanity check: no lost bits during pointer conversion
+  BX_ASSERT (sizeof(masked) >= sizeof(vector));
+  // sanity check: after realignment, everything fits in allocated space
+  BX_ASSERT (vector+bytes <= actual_vector+bytes+test_mask);
+  BX_INFO (("allocated memory at %p. after alignment, vector=%p", 
+       actual_vector, vector));
+}
+#endif
+
+// We can't use this because alloc_vector_aligned uses BX_INFO, but the object does not yet exists
+/*
+#if BX_PROVIDE_CPU_MEMORY
+  // BX_MEM_C constructor
+
+BX_MEM_C::BX_MEM_C(size_t memsize)
+{
+  char mem[6];
+  snprintf(mem, 6, "MEM%d", BX_SIM_ID);
+  put(mem);
+  settype(MEMLOG);
+
+  vector = NULL;
+  actual_vector = NULL;
+  alloc_vector_aligned (memsize, BX_MEM_VECTOR_ALIGN);
+  len    = memsize;
+  megabytes = len / (1024*1024);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+*/
+
+
+#if BX_PROVIDE_CPU_MEMORY
+// BX_MEM_C destructor
+BX_MEM_C::~BX_MEM_C(void)
+{
+  if (this-> vector != NULL) {
+    delete [] actual_vector;
+    actual_vector = NULL;
+    vector = NULL;
+    }
+  else {
+    BX_DEBUG(("(%u)   memory not freed as it wasn't allocated!", BX_SIM_ID));
+    }
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+  void
+BX_MEM_C::init_memory(int memsize)
+{
+  BX_DEBUG(("Init $Id: misc_mem.cc,v 1.41 2003/09/10 16:34:56 vruppert Exp $"));
+  // you can pass 0 if memory has been allocated already through
+  // the constructor, or the desired size of memory if it hasn't
+  // BX_INFO(("%.2fMB", (float)(BX_MEM_THIS megabytes) ));
+
+#ifndef BX_USE_VMX
+  if (BX_MEM_THIS vector == NULL) {
+    // memory not already allocated, do now...
+    alloc_vector_aligned (memsize, BX_MEM_VECTOR_ALIGN);
+#endif
+    BX_MEM_THIS len    = memsize;
+    BX_MEM_THIS megabytes = memsize / (1024*1024);
+    BX_INFO(("%.2fMB", (float)(BX_MEM_THIS megabytes) ));
+#ifndef BX_USE_VMX
+    }
+#endif
+
+#if BX_DEBUGGER
+  if (megabytes > BX_MAX_DIRTY_PAGE_TABLE_MEGS) {
+    BX_INFO(("Error: memory larger than dirty page table can handle"));
+    BX_PANIC(("Error: increase BX_MAX_DIRTY_PAGE_TABLE_MEGS"));
+    }
+#endif
+
+    unsigned long nr_pages = megabytes * (1024 * 1024/getpagesize());
+
+    if ( (page_array = (unsigned long *) 
+                 malloc(nr_pages * sizeof(unsigned long))) == NULL)
+    {
+        BX_ERROR(("Could not allocate memory"));
+               return;
+    }
+
+    if ( xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages )
+    {
+        BX_ERROR(("Could not get the page frame list"));
+               return;
+    }
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE  (1 << PAGE_SHIFT)
+#define round_pgup(x)  (((x) + PAGE_SIZE-1) & ~ (PAGE_SIZE-1))
+
+    int npte_pages = 1 + (round_pgup(nr_pages * 4) / PAGE_SIZE); 
+
+    /* We don't map pte pages and the top 64k -- XXX: this could be a problem */
+    if ((vector = (Bit8u *) xc_map_foreign_batch(xc_handle, domid,
+                                                 PROT_READ|PROT_WRITE,
+                                                 page_array,
+                                                 nr_pages - npte_pages - 16)) == 0) {
+        BX_ERROR(("Could not map guest physical"));
+        return;
+    }
+
+    BX_MEM_THIS dma_limit = (nr_pages - npte_pages - 16) << PAGE_SHIFT;
+    BX_INFO(("DMA limit: %lx", BX_MEM_THIS dma_limit));
+
+    shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, 
+                                       PROT_READ|PROT_WRITE, 
+                                       page_array[nr_pages - 1]);
+
+    /* Initialize shared page */
+    memset(shared_page, 0, PAGE_SIZE);
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+
+#if BX_PROVIDE_CPU_MEMORY
+  void
+  // Values for type :
+  // 0 : System Bios
+  // 1 : VGA Bios
+  // 2 : Optional ROM Bios
+BX_MEM_C::load_ROM(const char *path, Bit32u romaddress, Bit8u type)
+{
+  struct stat stat_buf;
+  int fd, ret;
+  unsigned long size, offset;
+
+  if (*path == '\0') {
+    if (type == 2) {
+      BX_PANIC(( "ROM: Optional BIOS image undefined."));
+      }
+    else if (type == 1) {
+      BX_PANIC(( "ROM: VGA BIOS image undefined."));
+      }
+    else {
+      BX_PANIC(( "ROM: System BIOS image undefined."));
+      }
+    return;
+    }
+  // read in ROM BIOS image file
+  fd = open(path, O_RDONLY
+#ifdef O_BINARY
+            | O_BINARY
+#endif
+           );
+  if (fd < 0) {
+    if (type < 2) {
+      BX_PANIC(( "ROM: couldn't open ROM image file '%s'.", path));
+      }
+    else {
+      BX_ERROR(( "ROM: couldn't open ROM image file '%s'.", path));
+      }
+    return;
+    }
+  ret = fstat(fd, &stat_buf);
+  if (ret) {
+    if (type < 2) {
+      BX_PANIC(( "ROM: couldn't stat ROM image file '%s'.", path));
+      }
+    else {
+      BX_ERROR(( "ROM: couldn't stat ROM image file '%s'.", path));
+      }
+    return;
+    }
+
+  size = stat_buf.st_size;
+
+  if ( (romaddress + size) > BX_MEM_THIS len ) {
+    BX_PANIC(( "ROM: ROM address range > physical memsize!"));
+    return;
+    }
+
+  offset = 0;
+  while (size > 0) {
+    ret = read(fd, (bx_ptr_t) &BX_MEM_THIS vector[romaddress + offset], size);
+    if (ret <= 0) {
+      BX_PANIC(( "ROM: read failed on BIOS image: '%s'",path));
+      }
+    size -= ret;
+    offset += ret;
+    }
+  close(fd);
+  BX_INFO(("rom at 0x%05x/%u ('%s')",
+                       (unsigned) romaddress,
+                       (unsigned) stat_buf.st_size,
+                       path
+               ));
+}
+#endif // #if BX_PROVIDE_CPU_MEMORY
+
+#if BX_PCI_SUPPORT
+  Bit8u* BX_CPP_AttrRegparmN(1)
+BX_MEM_C::pci_fetch_ptr(Bit32u addr)
+{
+  if (bx_options.Oi440FXSupport->get ()) {
+    switch (DEV_pci_rd_memtype (addr)) {
+      case 0x1:   // Read from ShadowRAM
+        return (&BX_MEM_THIS shadow[addr - 0xc0000]);
+
+      case 0x0:   // Read from ROM
+        return (&BX_MEM_THIS vector[addr]);
+      default:
+        BX_PANIC(("pci_fetch_ptr(): default case"));
+        return(0);
+      }
+    }
+  else
+    return (&BX_MEM_THIS vector[addr]);
+}
+#endif
+
+
+#if ( BX_DEBUGGER || BX_DISASM || BX_GDBSTUB)
+  bx_bool
+BX_MEM_C::dbg_fetch_mem(Bit32u addr, unsigned len, Bit8u *buf)
+{
+  if ( (addr + len) > this->len ) {
+    BX_INFO(("dbg_fetch_mem out of range. 0x%x > 0x%x",
+      addr+len, this->len));
+    return(0); // error, beyond limits of memory
+    }
+  for (; len>0; len--) {
+    if ( (addr & 0xfffe0000) == 0x000a0000 ) {
+      *buf = DEV_vga_mem_read(addr);
+      }
+    else {
+#if BX_PCI_SUPPORT == 0
+      *buf = vector[addr];
+#else
+      if ( bx_options.Oi440FXSupport->get () &&
+          ((addr >= 0x000C0000) && (addr <= 0x000FFFFF)) ) {
+        switch (DEV_pci_rd_memtype (addr)) {
+          case 0x1:  // Fetch from ShadowRAM
+            *buf = shadow[addr - 0xc0000];
+//          BX_INFO(("Fetching from ShadowRAM %06x, len %u !", (unsigned)addr, (unsigned)len));
+            break;
+
+          case 0x0:  // Fetch from ROM
+            *buf = vector[addr];
+//          BX_INFO(("Fetching from ROM %06x, Data %02x ", (unsigned)addr, *buf));
+            break;
+          default:
+            BX_PANIC(("dbg_fetch_mem: default case"));
+          }
+        }
+      else
+        *buf = vector[addr];
+#endif  // #if BX_PCI_SUPPORT == 0
+      }
+    buf++;
+    addr++;
+    }
+  return(1);
+}
+#endif
+
+#if BX_DEBUGGER || BX_GDBSTUB
+  bx_bool
+BX_MEM_C::dbg_set_mem(Bit32u addr, unsigned len, Bit8u *buf)
+{
+  if ( (addr + len) > this->len ) {
+    return(0); // error, beyond limits of memory
+    }
+  for (; len>0; len--) {
+    if ( (addr & 0xfffe0000) == 0x000a0000 ) {
+      DEV_vga_mem_write(addr, *buf);
+      }
+    else
+      vector[addr] = *buf;
+    buf++;
+    addr++;
+    }
+  return(1);
+}
+#endif
+
+  bx_bool
+BX_MEM_C::dbg_crc32(unsigned long (*f)(unsigned char *buf, int len),
+    Bit32u addr1, Bit32u addr2, Bit32u *crc)
+{
+  unsigned len;
+
+  *crc = 0;
+  if (addr1 > addr2)
+    return(0);
+
+  if (addr2 >= this->len) {
+    return(0); // error, specified address past last phy mem addr
+    }
+  
+  len = 1 + addr2 - addr1;
+  *crc = f(vector + addr1, len);
+
+  return(1);
+}
+
+
+  Bit8u * BX_CPP_AttrRegparmN(3)
+BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, Bit32u a20Addr, unsigned op)
+  // Return a host address corresponding to the guest physical memory
+  // address (with A20 already applied), given that the calling
+  // code will perform an 'op' operation.  This address will be
+  // used for direct access to guest memory as an acceleration by
+  // a few instructions, like REP {MOV, INS, OUTS, etc}.
+  // Values of 'op' are { BX_READ, BX_WRITE, BX_RW }.
+
+  // The other assumption is that the calling code _only_ accesses memory
+  // directly within the page that encompasses the address requested.
+{
+  if ( a20Addr >= BX_MEM_THIS len )
+    return(NULL); // Error, requested addr is out of bounds.
+  if (op == BX_READ) {
+    if ( (a20Addr > 0x9ffff) && (a20Addr < 0xc0000) )
+      return(NULL); // Vetoed!  Mem mapped IO (VGA)
+#if !BX_PCI_SUPPORT
+    return( (Bit8u *) & vector[a20Addr] );
+#else
+    else if ( (a20Addr < 0xa0000) || (a20Addr > 0xfffff)
+              || (!bx_options.Oi440FXSupport->get ()) )
+      return( (Bit8u *) & vector[a20Addr] );
+    else {
+      switch (DEV_pci_rd_memtype (a20Addr)) {
+        case 0x0:   // Read from ROM
+          return ( (Bit8u *) & vector[a20Addr]);
+        case 0x1:   // Read from ShadowRAM
+          return( (Bit8u *) & shadow[a20Addr - 0xc0000]);
+        default:
+          BX_PANIC(("getHostMemAddr(): default case"));
+          return(0);
+        }
+      }
+#endif
+    }
+  else { // op == {BX_WRITE, BX_RW}
+    Bit8u *retAddr;
+
+    if ( (a20Addr < 0xa0000) || (a20Addr > 0xfffff) ) {
+      retAddr = (Bit8u *) & vector[a20Addr];
+      }
+#if !BX_PCI_SUPPORT
+    else
+      return(NULL); // Vetoed!  Mem mapped IO (VGA) and ROMs
+#else
+    else if ( (a20Addr < 0xc0000) || (!bx_options.Oi440FXSupport->get ()) )
+      return(NULL); // Vetoed!  Mem mapped IO (VGA) and ROMs
+    else if (DEV_pci_wr_memtype (a20Addr) == 1) {
+      // Write to ShadowRAM
+      retAddr = (Bit8u *) & shadow[a20Addr - 0xc0000];
+      }
+    else
+      return(NULL); // Vetoed!  ROMs
+#endif
+
+#if BX_SupportICache
+    cpu->iCache.decWriteStamp(cpu, a20Addr);
+#endif
+
+    return(retAddr);
+    }
+}
diff --git a/tools/ioemu/mk/helix.mk b/tools/ioemu/mk/helix.mk
new file mode 100644 (file)
index 0000000..c9bc04c
--- /dev/null
@@ -0,0 +1,7 @@
+LDFLAGS  += -g
+CXXFLAGS += -g  -I../../../tools/libxc -I../../../xen/include/public
+clean:
+       $(RM) -f *.o *~ lib*.a device-model
+
+install::
+